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

因为我的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 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这个问题。如果使用自引用来防止用户数据被收集,那么弱引用将不起作用。对于其他用途,您的解决方案很好,不过我更喜欢在库环境中使用弱表。