Lua5.1 garbage collection control
OK, so I have a C ++ class that works with Lua using SWIG. The script creates an object, but the manager class also has a pointer to the object, so it can be modified in C ++ (or another script) for any reason.
The problem is, when the script finishes freeing the object, how can I control what the garbage collector is collecting without having to implement the gc meta method?
Here's an example:
--Script that creates the object
someObject = Utils.Object("Obj name");
The object is now registered with the manager so that the rest of the application (and other scripts) can access it.
--Another script obj = ObjManager:GetObject(0);
Obviously this is not a very realistic example, but hopefully it illustrates my question. Is there a way to veto a garbage collector without the gc metamethod in C ++?
Just to clarify, the manager is in C ++ and Utils is the name of the module that the public class is in. Also, the object is registered with the manager in its constructor.
Thanks in advance.
a source to share
Lua GC only knows about references contained in Lua, which is a reasonable implementation constraint. This means that the lifetime of the object is under the control of Lua. If an object created by the execution of one script or function needs to be accessible to subsequent scripts or functions, a reference to it must be kept in Lua state so that the GC knows it is still in use. Otherwise, it is indistinguishable from garbage and can be discarded at any time.
This is one of the purposes of the Lua registry table. The C side can easily reference any Lua object by placing it in a registry table. The key can either be a unique value known to the C library (variable address static
converted to light user data is often a good choice as it cannot collide with any key from any other library). Alternatively, the function call luaL_ref(L, LUA_REGISTRYINDEX)
pushes the item to the top of the stack into the registry table and returns a unique integer key. This works well for keeping the script callback function in such a way that both shields the function from the GC and allows it to be "pointer" (integer key) stored in a C structure so that it can be retrieved and called later.
Note that it luaL_ref()
can be used to manage references in any table, so it might well make sense to use a table that is private to your module for this purpose, rather than a global registry table. In this case, the table itself ObjManager
might be a good candidate.
a source to share
Yes; have Utils.Object things object in a private table. Then it will never be compiled, but you can play games (code not tested):
do
local retained = { } -- table forces objects to be retained
local old_util_object = Util.Object
Util.Object = function(...)
local obj = old_util_object(...)
retained[obj] = true
return obj
end
Util.Free = function(obj)
assert(retained[obj])
retained[obj] = nil -- now obj can be garbage-collected
end
end
If you want to solve the same problem on the C ++ side, have your C ++ code allocate a private table and put it in the Lua registry. Then you can play the same insert / delete game using only the C API instead of the Lua source. Assuming you are familiar with the Lua C API, this is simple. If you haven't used the C API before, there will never be a better time to start learning.
a source to share