I'm working on a Lua binding for a C library where each object allocated by the C library is stored as a Lua userdata object with a metatable that handles method calls for the object and also adds a __gc function for the garbage collector so that the C object is deleted as soon as there are no more references to it in the Lua script. This basically works but I'm wondering what the best way to solve the problem of garbage collection is in this case?
What bothered me was the "as soon as" here, the Lua GC does not guarantee immediate garbage collection. The GC runs a few steps each time the interpreter or your C code allocates an object, but it can take a long time before an object is actually collected. The __close metamethod is used to get around this problem in Lua 5.4.
Now "listitem" is marked for garbage collection even though it is still referenced by "list" because it has been inserted into the list using "list:insertitem()".
That assignment does not mark the object for garbage collection, it just removes the reference to the object from the interpreter register set. The garbage collector will eventually detect that there are no references to the object and start collecting it.
In this case you need to provide a reference to any object you store in the 'mylist' structure so the GC can find it. I usually create a table and store it in the uservalue field of the userdata object. When you add an item to the 'mylist' structure you then also add it to the table. The advantage over using the registry is that you do not have to explicitly delete the registry entries in your mylist __gc code.
One side note: when you allocate a userdata object, initialize the fields before you call 'setmetatable', especially when the metatable has a __gc field. If 'alloc_the_list' in your code throws an error the 'obj' field is not in a known state, and when __gc is called it could cause a crash.