为什么我们需要两次调用Lua的collectgarbage()?

时间:2015-02-04 11:26:55

标签: lua garbage-collection

我遇到了several places,人们拨打collectgarbage() 两次来完成所有未使用的对象。

为什么?为什么单个电话不够?为什么不打三个电话?

当我尝试下面的代码时(在Lua 5.2上),对象最终确定(意思是:只需调用__gc就可以调用它的collectgarbage

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

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

1 个答案:

答案 0 :(得分:15)

Lua编程第3版§17.6终结器中进行了解释。简而言之,这是因为复活。

终结器是与将要收集该对象时调用的对象关联的函数。 Lua使用__gc metamethod实现终结器。

问题是,当调用终结器时,在某些情况下对象必须处于活动状态。 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,因此在A完成之前无法收集B。在运行终结器之前,Lua必须复活BA

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

  

由于复活,具有终结器的对象分两个阶段收集。   收集器第一次检测到具有终结器的对象无法访问时,收集器会重新生成对象并对其进行排队以进行最终确定。一旦终结器运行,Lua就会将对象标记为已完成。下次收集器检测到对象不可访问时,它会删除该对象。如果要确保程序中的所有垃圾都已实际释放,则必须调用collectgarbage两次;第二个调用将删除第一次调用期间最终确定的对象。