【问题标题】:How do I unload/destroy a lua script?如何卸载/销毁 lua 脚本?
【发布时间】:2020-08-17 02:59:07
【问题描述】:

我正在尝试制作一个非常简单的 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++)
{
// Since I don't unload the previous file, does this cause a memory leak until  lua_close is called?
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: " << 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 << "Error Calling Function In Script: " << 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 << "Error Invalid Function In Script: " << file_path << "::" << function_name << std::endl;
  }
  }
}

lua_close(m_lua_state);

【问题讨论】:

  • 如果脚本只定义了一个函数,则无需“卸载”脚本。多次重新定义全局函数不会泄漏内存。之前的函数将在最近的 GC 事件中收集。但是函数本身(在执行时)会吃掉内存。

标签: c++ lua


【解决方案1】:

如果 unload 是指撤消运行某些 Lua 代码的影响,那么除非在运行代码之前保存珍贵的状态,否则无法完成。这可以通过对代码进行沙箱处理来完成。

如果你只是想删除一个 Lua 表,请将所有对它的引用设置为 nil,并让该表自动或手动进行垃圾收集。

【讨论】:

    【解决方案2】:

    当您加载一个 lua 文件时,您实际上是在执行它的代码。它不像 dll 或其他语言的东西:

    int luaL_dofile (lua_State *L, const char *filename);
    加载并运行给定的文件。定义为如下宏:

    如果你的文件是这样的:

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

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

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

    以 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 现在是一个“余额”属性为 100.00 的表和一个指向具有存款功能的 Account 表的元表。如果您更改存款函数以打印余额并重新加载文件,它将替换全局“帐户”表和函数,但表“a”仍将具有原始帐户表,因为它是可元表的。所以调用 'a.deposit' 仍然不会打印值。

    【讨论】:

      猜你喜欢
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多