【问题标题】:Controlling Lua5.1's garbage collector控制 Lua5.1 的垃圾收集器
【发布时间】:2010-10-24 09:53:39
【问题描述】:

好的,所以我有一个使用 SWIG 向 Lua 公开的 C++ 类。该脚本创建对象,但管理器类也有一个指向该对象的指针,因此无论出于何种原因都可以在 C++(或其他脚本)中对其进行修改。

问题是,当脚本完成对象被释放时,如何控制垃圾收集器收集的内容而无需实现 gc 元方法?

这是一个例子:

--Script that creates the object
someObject = Utils.Object("Obj name");

现在对象已经向管理器注册了自己,因此应用程序的其余部分(和其他脚本)可以访问它。

--Another script
obj = ObjManager:GetObject(0);

显然不是一个非常现实的例子,但希望它能说明我的问题。有没有办法在 C++ 中不使用 gc 元方法来否决垃圾收集器?

只是为了澄清管理器是用 C++ 编写的,而 Utils 是包含公开类的模块名称。该对象还在其构造函数中将自身注册到管理器。

提前致谢。

【问题讨论】:

  • 如果您标记每个代码片段以了解代码片段是 C++ 还是 Lua,这将有所帮助。
  • 对,我用 lua cmets 标记了它们。

标签: c++ garbage-collection lua


【解决方案1】:

Lua 的 GC 只知道 Lua 中的引用,这是一个合理的实现约束。这意味着对象的生命周期在 Lua 的控制之下。如果通过执行一个脚本或函数创建的对象需要供以后的脚本或函数使用,则必须在 Lua 状态中保留对它的引用,以便 GC知道它仍在使用中。否则与垃圾无异,随时可能被丢弃。

这是 Lua 注册表的用途之一。 C 端可以通过将 Lua 对象放在注册表中轻松地保存对任何 Lua 对象的引用。键可以是 C 库已知的某个唯一值(转换为轻用户数据的 static 变量的地址通常是一个不错的选择,因为它不会与任何其他库中的任何键发生冲突)。或者,函数调用luaL_ref(L, LUA_REGISTRYINDEX) 将把该项放在注册表中堆栈的顶部,并返回一个唯一的整数键。这适用于存储脚本提供的回调函数,既保护函数免受 GC 影响,又允许将指向它的“指针”(整数键)存储在 C 结构中,以便可以检索和调用它稍后。

请注意,luaL_ref() 可用于管理任何表中的引用,因此使用模块专用的表而不是全局注册表可能非常有意义。在这种情况下,表ObjManager 本身可能是一个不错的候选对象。

【讨论】:

    【解决方案2】:

    是的;让 Utils.Object 将对象填充到私有表中。那么它将永远被收集,但你可以玩游戏(代码未测试):

    do
      local retained = { }  -- table forces objects to be retained
      local old_util_object = Util.Object
      Util.Object = function(...)
        local obj = old_util_object(...)
        retained[obj] = true
        return obj
      end
      Util.Free = function(obj)
        assert(retained[obj])
        retained[obj] = nil  -- now obj can be garbage-collected
      end
    end
    

    如果你想在 C++ 端解决同样的问题,让你的 C++ 代码分配一个私有表并将它放在 Lua 注册表中。然后你可以玩相同的插入/删除游戏,只使用 C API 而不是 Lua 源。假设您熟悉 Lua 的 C API,这很简单。如果您之前没有使用过 C API,那么现在就是开始学习的最佳时机。

    【讨论】:

    • 感谢您的回答,但它并没有真正帮助。我正在寻找一种在 C/++ 中执行此操作的方法。我澄清了我的问题以表明这一点。
    猜你喜欢
    • 2019-06-07
    • 1970-01-01
    • 2012-04-20
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    • 2013-04-01
    相关资源
    最近更新 更多