Lua 自引用用户数据和垃圾收集
因为我的userdata对象引用它们自己,所以我需要删除和nil一个变量,垃圾收集器才能工作 Lua代码:Lua 自引用用户数据和垃圾收集,lua,Lua,因为我的userdata对象引用它们自己,所以我需要删除和nil一个变量,垃圾收集器才能工作 Lua代码: obj = object:new() -- -- Some time later obj:delete() -- Removes the self reference obj = nil -- Ready for collection C代码: typedef struct { int self; // Reference to the object int
obj = object:new()
--
-- Some time later
obj:delete() -- Removes the self reference
obj = nil -- Ready for collection
C代码:
typedef struct {
int self; // Reference to the object
int callback; // Reference to a Lua function
// Other members and function references removed
} Object;
// Called from Lua to create a new object
static int object_new( lua_State *L ) {
Object *obj = lua_newuserdata( L, sizeof( Object ) );
// Create the 'self' reference, userdata is on the stack top
obj->self = luaL_ref( L, LUA_REGISTRYINDEX );
// Put the userdata back on the stack before returning
lua_rawgeti( L, LUA_REGISTRYINDEX, obj->self );
// The object pointer is also stored outside of Lua for processing in C
return 1;
}
// Called by Lua to delete an object
static int object_delete( lua_State *L ) {
Object *obj = lua_touserdata( L, 1 );
// Remove the objects self reference
luaL_unref( L, LUA_REGISTRYINDEX, obj->self );
return 0;
}
// Called from Lua to set a callback function
static int object_set_callback( lua_State *L ) {
Object *obj = lua_touserdata( L, 1 );
// Unref an existing callbacks
if ( obj->callback != 0 ) {
luaL_unref( L, LUA_REGISTRYINDEX, obj->callback );
obj->callback = 0;
}
// Set the new callback - function is on top of the stack
obj->callback = luaL_ref( L, LUA_REGISTRYINDEX );
}
// Called from C to call a Lua function for the obj
static void do_callback( Object *obj ) {
// Push the Lua function onto the stack
lua_rawgeti( L, LUA_REGISTRYINDEX, obj->callback );
// Push the userdata onto the stack
lua_rawgeti( L, LUA_REGISTRYINDEX, obj->self );
// Call the function
lua_call( L, 1, 0 );
}
是否有某种方法可以在Lua中将对象设置为nil,并自动调用delete()方法?或者,delete方法是否可以将引用该对象的所有变量置零?是否可以将自我引用设置为“弱”
编辑1:我加入了代码来说明对象引用自身的原因;请参阅do_回调函数。每个对象都是树状结构的一部分,大部分处理是用C语言完成的,但用户可以设置在特定条件下调用的自定义Lua函数
编辑2:另一个可能的解决方案出现在脑海中;当我需要将对象传递给Lua时,是否可以在全局索引中查找该对象,而不是每个obj都保留对自身的引用,使用其地址作为键?您可以尝试在注册表中创建一个弱表并将引用存储在那里,这样,将对象的所有引用设置为nil将使其可用于gc 我不会给出正常的答案,因为我不知道如何解决您的整个问题,但您是否研究过Lua的_gc-metamethod?userdata具有_gc回调;但是,直到在delete()中删除自引用,并且指向userdata的所有变量都为零之后,才会调用它。为什么需要自引用?在C端,您可以存储(Object*)obj,并依靠uu gc进行清理;在Lua方面,您有obj。我已经更新了代码,以说明我如何/为什么保留自引用以从C将对象传递回Lua。好的,在这种情况下,Neruz的建议是好的。在Lua中未保留对obj的(强)引用后,将收集obj。如果唯一的引用来自obj,您可能需要对回调函数进行强引用,在这种情况下,您需要obj的_gc方法来删除对回调的引用,以便可以收集回调。这取决于自引用的用途,所以我问了drtwox这个问题。如果使用自引用来防止用户数据被收集,那么弱引用将不起作用。对于其他用途,您的解决方案很好,不过我更喜欢在库环境中使用弱表。