Ответ 1
Это объясняется в Программе в Lua 3rd edition §17.6 Finalizers. Короче говоря, это из-за воскресения.
Финализатор - это функция, связанная с объектом, который вызывается, когда этот объект собирается собираться. 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
, поэтомуA
невозможно собрать до завершенияB
. Lua должен возобновить какB
, так иA
перед запуском этого финализатора.
Воскресение является причиной вызова collectgarbage
дважды:
Из-за воскрешения объекты с финализаторами собираются в две фазы. В первый раз, когда коллекционер обнаруживает, что объект с финализатором недоступен, сборщик воскрешает объект и ставит его в очередь для завершения. Как только его финализатор работает, Lua отмечает объект как завершенный. В следующий раз, когда коллекционер обнаружит, что объект недоступен, он удаляет объект. Если вы хотите, чтобы весь мусор в вашей программе был фактически выпущен, вы должны дважды позвонить
collectgarbage
; второй вызов удалит объекты, которые были завершены во время первого вызова.