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

Nic*_* M. 17 lua garbage-collection

我曾经遇到过几个 地方,人们称之为collectgarbage() 两次来完成所有未使用的对象.

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

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

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

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

Yu *_*Hao 16

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

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

问题是,当调用终结器时,在某些情况下对象必须是活的.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
Run Code Online (Sandbox Code Playgroud)

B访问的终结器A,因此A无法在最终确定之前收集B.Lua中必须既复活BA运行终结之前.

复活是collectgarbage两次召唤的原因:

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