如何卸载/销毁Lua脚本?

我正在尝试制作一个非常简单的Lua包装器,用于加载和运行多个Lua脚本。我担心的是,我没有看到任何关于如何正确销毁/删除已加载的脚本的文档,而不完全销毁lua_State本身。

是否可以删除/卸载已加载的Lua脚本?这是不必要的还是持续调用luaL_dofile会导致内存泄漏?

简化的问题... 如果我在同一lua_State对象上调用luaL_dofile,是否会导致内存泄漏或问题,还是Lua在后端处理它时加载新脚本?

这里是一个演示...

lua_State* m_lua_state = luaL_newstate();
lua_gc(m_lua_state, LUA_GCSTOP, 0);
luaL_openlibs(m_lua_state);
lua_gc(m_lua_state, LUA_GCRESTART, 0);

for(int i = 0; i < 99999999; i++)
{
// 因为我不卸载以前的文件,这会导致内存泄漏,直到调用lua_close吗?
if (luaL_dofile(m_lua_state, file_path.c_str()) != LUA_OK)
{
   std::string error_msg = lua_tostring(m_lua_state, -1);
   std::cout << "错误:" << error_msg << std::endl;
   return false;
}
else
{
   lua_getglobal(m_lua_state, function_name.c_str());

   if (lua_isfunction(m_lua_state, -1))
   {
     int stack_size = lua_gettop(m_lua_state);

     int number_of_args = 0;
     if (lua_pcall(m_lua_state, number_of_args, 0, 0) != LUA_OK)
     {
        std::cout << "调用脚本中的函数错误:" << file_path << "::" << function_name << " - " << lua_tostring(m_lua_state, -1) << std::endl;
     }
     int total_return_values = lua_gettop(m_lua_state) - stack_size;
  }
  else
  {
     std::cout << "脚本中的函数无效错误:" << file_path << "::" << function_name << std::endl;
  }
  }
}

lua_close(m_lua_state);
点赞
用户13228003
用户13228003

如果你所谓的“卸载”是指撤销运行一些 Lua 代码的影响,那么,除非你在运行代码之前保存宝贵的状态,否则无法完成。这可以通过给代码设置沙盒实现。

如果你只想删除一个 Lua 表,设置所有对它的引用为 nil,然后让表被自动或手动垃圾回收。

2020-08-17 05:44:46
用户369792
用户369792

当你加载一个 Lua 文件时,你实际上是在执行它的代码。和其他语言的 DLL 或其他文件类型不同:

int luaL_dofile (lua_State *L, const char *filename);

加载并运行指定的文件。它定义为以下宏:

如果你的文件内容如下:

function sayHello()
  print('Hello, world!')
end

那么加载该文件将在全局对象上创建一个名为 'sayHello' 的函数。如果再次加载该文件,它将用新函数替换现有函数,而且不会出现内存泄漏。调用 'sayHello' 的任何人都将在全局对象上调用新函数,除非他们已经保存了原始函数的引用。代码通常这样做,因为调用局部变量比调用全局函数稍微快一些。例如,如果另一个文件在顶部有 local sayhi = sayHello,那么对 'sayhi' 的任何调用都将调用原始函数。

如果你正在创建类并期望数据保留,任何在重新加载之前创建的对象(Lua 表)仍将引用旧类的 metatable。你的新类的代码不会自动应用于在重新加载之前创建的类。

以 Lua 文档中的示例为例:

Account = {}

function Account:deposit (v)
  self.balance = self.balance + v
end

function Account:new (o)
  o = o or {}   -- create object if user does not provide one
  setmetatable(o, self)
  self.__index = self
  return o
end

a = Account:new{balance = 0}
a:deposit(100.00)

现在,a 是一个具有 'balance' 属性为 100.00 和元表指向 Account 表的表。如果你修改 deposit 函数以便打印余额并重新加载文件,它将替换全局 'Account' 表和函数,但表 'a' 将仍然具有原始的 Account 表作为它的元表。因此,调用 'a.deposit' 将仍然不会打印该值。

2020-08-17 22:39:43