自引用用户数据和垃圾回收

时间:2010-05-02 23:44:25

标签: 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 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()方法?或者,删除方法可以为所有引用该对象的变量吗?自我引用可以变得“弱”吗?

编辑1:我已经包含了代码来说明对象引用自身的原因;看到do_callback函数。每个对象都是树状结构的一部分,大部分处理在C中完成,但用户可以设置在某些条件下调用的自定义Lua函数。

编辑2:另一种可能的解决方案浮现在脑海中;而不是每个obj保持对自身的引用,当我需要将其地址作为键传递给Lua时,我可以在全局索引中查找对象吗?

1 个答案:

答案 0 :(得分:1)

您可以尝试在注册表中创建一个弱表并在那里存储您的引用,这样将对象的所有引用设置为nil应该使它可用于gc。