我能够在无需调用整个GC的情况下“清理”弱表吗?

我有一个带有弱引用键的表格。我用它来“注册”事件:

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 中有一些“幻影引用”,并且为基本上不再存在的对象执行回调。例如,我创建一个按钮并将其与“单击”事件关联。然后我删除这个按钮(将它设置为 nil)。在接下来的一秒钟里,我仍然可以“单击它”,这是很遗憾的。

我找到的唯一解决办法是在 launchEvents 内部手动运行 GC:

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

但是这似乎有点过度杀伤力。 launchEvents 可能会被调用多次每秒。我为了清理一个表格而调用了完整的垃圾回收循环。

有没有其他方法可以解决这个问题?我能否“垃圾收集”或“清理”仅限于一个弱表?

PS:顺便说一下,我使用的是 Lua 5.1

原文链接 https://stackoverflow.com/questions/9131352

点赞
stackoverflow用户734069
stackoverflow用户734069

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

你的设计基本上是有缺陷的。如果你想收集一堆事件,然后执行它们,然后再收集一堆事件,然后再执行它们,那么你必须这样做。你需要显式地 丢弃 旧的事件;不要只是把它们放在一个弱引用表中,并期望 GC 会将引用置为 nil

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

2012-02-03 17:38:38