Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do we need to call Lua's collectgarbage() twice?

I have encountered several places where people call collectgarbage() twice to finalize all unused objects.

Why is that? Why isn't a single call enough? Why not three calls?

When I try the following code (on Lua 5.2), the object gets finalized (meaning: its __gc gets called) with just a single call to collectgarbage:

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

Does this mean one call is enough?

like image 225
Niccolo M. Avatar asked Feb 04 '15 11:02

Niccolo M.


People also ask

How does the Lua garbage collector work?

Lua uses a garbage collector that runs from time to time to collect dead objects when they are no longer accessible from the Lua program. All objects including tables, userdata, functions, thread, string and so on are subject to automatic memory management.

Does Lua use garbage collection?

Lua does automatic memory management. A program only creates objects (tables, functions, etc.); there is no function to delete objects. Lua automatically deletes objects that become garbage, using garbage collection.


1 Answers

It's explained in Programming in Lua 3rd edition §17.6 Finalizers. In short, it's because of resurrection.

A finalizer is a function associated with an object that is called when that object is about to be collected. Lua implements finalizers with __gc metamethod.

The problem is, when the finalizers are called, the object must be alive in some cases. PiL explains it with this example:

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

The finalizer for B accesses A, so A cannot be collected before the finalization of B. Lua must resurrect both B and A before running that finalizer.

Resurrection is the reason of calling collectgarbage twice:

Because of resurrection, objects with finalizers are collected in two phases. The first time the collector detects that an object with a finalizer is not reachable, the collector resurrects the object and queues it to be finalized. Once its finalizer runs, Lua marks the object as finalized. The next time the collector detects that the object is not reachable, it deletes the object. If you want to ensure that all garbage in your program has been actually released, you must call collectgarbage twice; the second call will delete the objects that were finalized during the first call.

like image 116
Yu Hao Avatar answered Oct 14 '22 16:10

Yu Hao