【问题标题】:Why do we need to call Lua's collectgarbage() twice?为什么我们需要调用 Lua 的 collectgarbage() 两次?
【发布时间】:2015-04-03 21:44:54
【问题描述】:

我遇到过severalplaces,人们调用collectgarbage()两次来完成所有未使用的对象。

这是为什么呢?为什么一个电话不够?为什么不是三个电话?

当我尝试以下代码(在 Lua 5.2 上)时,只需一次调用 collectgarbage,对象就会完成(意思是:它的 __gc 被调用):

do
  local x = setmetatable({},{
    __gc = function() print("works") end
  })
end
collectgarbage()
os.exit()

这是否意味着一个电话就足够了?

【问题讨论】:

    标签: lua garbage-collection


    【解决方案1】:

    在 Lua 中编程第 3 版第 17.6 节终结器中对此进行了解释。简而言之,就是因为复活。

    终结器是与对象相关联的函数,当该对象即将被收集时会调用该函数。 Lua 使用 __gc 元方法实现终结器。

    问题是,当调用终结器时,在某些情况下对象必须是活动的。 PiL 用这个例子来解释它:

    A = {x = "this is A"}
    B = {f = A}
    setmetatable(B, {__gc = function (o) print(o.f.x) end})
    A, B = nil
    collectgarbage() --> this is A
    

    B 的终结器访问A,因此在B 的终结之前无法收集A。在运行终结器之前,Lua 必须同时恢复 BA

    复活是调用collectgarbage两次的原因:

    由于复活,具有终结器的对象分两个阶段收集。 收集器第一次检测到带有终结器的对象不可访问时,收集器会复活该对象并将其排队等待终结。一旦它的终结器运行,Lua 将对象标记为终结。下次收集器检测到对象不可访问时,它会删除该对象。如果你想确保你程序中的所有垃圾都被真正释放,你必须调用collectgarbage两次;第二次调用将删除在第一次调用期间完成的对象。

    【讨论】:

    • 引用“第二次调用将删除在第一次调用期间完成的对象”(和“下次收集器检测到 [...] 它删除对象”)说,如果我正确理解,终结器 (__gc) 在 [end of the] first 调用 collectgarbage() 时运行。然后,对coollectgarbagesecond 调用只是释放内存(手动:“对象内存在下一个垃圾收集周期中被释放”。PiL:参见前面的引用)。我自己的例子(我的问题中的代码)据说“证明”了我的这种理解。但是...
    • ... 但是我的理解一定是错误的,因为我的second link 证明它是错误的(即,终结器没有首先调用collectgarbage;请参阅“我必须再添加一个收集垃圾( ) call") 并且first link 包含一条评论(由用户)说“[calling] 两次确保调用所有终结器”(也许该评论是错误的)。所以我还是不知所措。
    • 糟糕,我看到了我的错误。我的first link 处理没有终结器的lua 5.1.4,所以它与我们完全无关。对不起。
    • 所以,我希望能明确地确认我的理解:__gcfirst 调用 collectgarbage() 时被调用,对吗?如果我理解错误,我是如何误解引号的? (顺便说一句,我确实阅读了您的代码示例。)
    猜你喜欢
    • 2019-08-07
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2022-07-12
    • 2019-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多