我遇到了several places,人们拨打collectgarbage() 两次来完成所有未使用的对象。
为什么?为什么单个电话不够?为什么不打三个电话?
当我尝试下面的代码时(在Lua 5.2上),对象最终确定(意思是:只需调用__gc
就可以调用它的collectgarbage
:
do
local x = setmetatable({},{
__gc = function() print("works") end
})
end
collectgarbage()
os.exit()
这是否意味着一个电话就足够了?
答案 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必须复活B
和A
。
复活是两次调用collectgarbage
的原因:
由于复活,具有终结器的对象分两个阶段收集。 收集器第一次检测到具有终结器的对象无法访问时,收集器会重新生成对象并对其进行排队以进行最终确定。一旦终结器运行,Lua就会将对象标记为已完成。下次收集器检测到对象不可访问时,它会删除该对象。如果要确保程序中的所有垃圾都已实际释放,则必须调用
collectgarbage
两次;第二个调用将删除第一次调用期间最终确定的对象。