【问题标题】:lua - Can I "clean up" a weak table without having to invoke the whole GC?lua - 我可以“清理”一个弱表而不必调用整个 GC 吗?
【发布时间】:2012-02-04 01:38:38
【问题描述】:

我有一张表,其键上的引用很弱。我用它来“注册”事件:

local events = setmetatable({}, {__mode="k"})

function registerEvent(reference, callback)
  events[reference] = callback
end

每隔一段时间,我都会执行所有“当前”的事件;也就是说,我解析events 表并执行它的回调。

function launchEvents()
  for reference,callback in pairs(events)
    callback(reference)
  end
end

此设置通常可以正常工作。一旦停止使用引用,它就会被垃圾回收,并且它的回调从 events 中消失。

问题是 - 有时 launchEvents 在引用已被消除时执行,但垃圾收集器仍未运行。在那种情况下,我在events 中有一些“幻像引用”,并且为基本上不再存在的对象执行了回调。例如,我创建了一个按钮并将其与“单击”事件相关联。然后我删除按钮(将其设置为零)。一秒钟左右,我仍然能够“点击它”,这很遗憾。

我能找到的唯一解决方法是在 launchEvents 中手动运行 GC:

function launchEvents()
  collectgarbage()
  for reference,callback in pairs(events)
    callback(reference)
  end
end

但这似乎有点矫枉过正。 launchEvents 每秒可能会被调用多次。我调用完整的垃圾回收周期只是为了清理一张表。

这种方法有替代方法吗?我可以只“收集”或“清理”一张薄弱的桌子吗?

PS:顺便说一句,我在 Lua 5.1 中

【问题讨论】:

  • 如果我对您的理解正确,您的程序完全不同(尽管相关)并且更大。使用自动内存管理,对象的删除是不确定的,因此不应该有语义影响,如果可以避免的话。相反,您需要一种方法来“删除”(出于所有语义目的 - 例如显示和可点击)独立于垃圾收集的对象。
  • 我不想明确“删除”。如果可能的话,我想将其限制为简单地设置对 nil 的引用。在这种情况下,“事件”几乎“屈服于”引用。真的“次要”。我认为引用“太重要了,不能与事件混在一起”。
  • 你必须是明确的。唯一隐含的是 GC 可能 删除不再(强烈)引用的对象。事实上,根本不收集是有效的,并且不应该破坏任何编写良好的程序,除非它们可能会耗尽内存。此外,我敢打赌,您的代码中的许多地方都不止一次引用了某个小部件(可能是隐式引用,例如临时引用或功能参数)。
  • 这实际上是一个非常好的观点。回调本身可能仍然隐式引用表 - 通过闭包。嗯..

标签: memory-management garbage-collection lua


【解决方案1】:

Lua 的垃圾收集器不是这样工作的。您可以通过调用lua_gcLUA_GCSTEP 逐步运行它。但这并不能保证它会调查任何特定的对象。

您的设计存在根本缺陷。如果你想收集一堆事件,然后执行它们,然后收集一堆新的事件,然后执行它们,那么你必须这样做。您需要明确扔掉旧事件;不要只是将它们放在一个弱表中并期望 GC 将 nil 排除在引用之外。

GC 不像 C 和 C++ 中的分配/释放。它是不规则的和不可靠的。您不应该依赖它来实现实际的设计功能。

【讨论】:

  • 我想我将不得不继续我目前的设置,即使它感觉不像它应该的那样自动化。那好吧。谢谢。
猜你喜欢
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多