lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I agree, the example shown marks the same object for finalization in the next cycle by setting again its metatable with the MT table that has a declared __gc key mapped to the function; when it is called (the object is being finalized), the finalizer here unconditionnally marks the object for being finalized in a later cycle. So the finalizer will be called indefinitely, once at each cycle.

  1. function MT:__gc()
  2.   self.cnt = self.cnt + 1
  3.   if self.cnt == 1 then
  4.     print("finalizing...")
  5.   else
  6.     print("and again...")
  7.   end
  8.   setmetatable(self, MT) -- here the error occurs
  9. end
This should be:
  1. function MT:__gc()
  2.   self.cnt = self.cnt + 1
  3.   if self.cnt == 1 then
  4.     print("finalizing...")
  5.     setmetatable(self, MT) -- mark for later finalization
  6.   else
  7.     print("and again...")
  8.   end
  9. end
This way only the first finalization (self.cnt==1) will  displaying "finalizing..."  and mark the object to be finalized again later (by restoring its metatable); the next cycle one will cause the finalizer to be called again but then self.cnt will be 2 and you'll get the message "and again...", but now the object is not marked to be finalized again, so it will be effectively collected (you should no longer see the "and again..." message more than once after the single "finalizing..." message).

It's not very well documented, but when a finalizer gets called on an object, just before calling it, the GC first clears the associated metatable if the object being finalized is a table: in the finalizer for an object whose type is 'table' or 'userdata', if you use getmetatable(self), it's not documented clearly if either you'll get nil, or you'll get the same metatable whose "__gc" entry is now nill, something that should be better, allowing you to store the "cnt" variable inside the metatable itself along with the "__gc" variable, instead of the object being finalized).


Le dim. 18 nov. 2018 à 12:08, Francisco Olarte <folarte@peoplecall.com> a écrit :
Gregor:

On Sun, Nov 18, 2018 at 9:51 AM Gregor Burghard <gburghard@gmx.de> wrote:
> here is a bug for Lua >= 5.3.0:
> When the finalizer method of a table resets the metatable of the same
> table, it will not be deleted after finalization. That means the table
> still exists and will be garbage collected again.

A more knowledgeable person may be give better details, but given
https://www.lua.org/manual/5.3/manual.html#2.5.1 says

<<You mark an object for finalization when you set its metatable and
the metatable has a field indexed by the string "__gc". >>

and a bit later..

<<Moreover, if the finalizer marks a finalizing object for
finalization again, its finalizer will be called again in the next
cycle where the object is unreachable>>

Seems like documented / expected behaviour to me ( a bit weird, but I
assume there is a reason, I can think of a couple of them ).

Francisco Olarte.