Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎲 GameMaker

Circular references and garbage collection in LUA

Started by DrTwox May 2, 2010 at 4:08 AM 0 replies 4.4k views
Original Post
DrTwox
DrTwox
Hi all, I'll start by saying this is probably a trivial concern, but it's been bothering me all afternoon. The collective wisdom here has never failed me before! My Lua userdata objects contain a reference to themselves so C functions can pass the objects to Lua callback functions:

// Code stripped down to the bare essentials!

typedef struct {
    int self; // Reference to the object
    int callback; // Reference to a function 
} Object;


// Called from Lua to create a new object
static int new_object( 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 from Lua to set a callback function for an object
static int set_callback( lua_State *L ) {
    Object *obj = lua_touserdata( L, 1 );

    // Unref any previous callback functions
    if ( obj->callback != 0 ) luaL_unref( L, LUA_REGISTRYINDEX, obj->callback );

    // Reference the new callback
    obj->callback = luaL_ref( L, LUA_REGISTRYINDEX );

    return 0;
}


// Called by Lua to delete an object
static int obj_delete( lua_State *L ) {
    Object *obj = lua_touserdata( L, 1 );

    if ( obj->callback != 0 ) luaL_unref( L, LUA_REGISTRYINDEX, obj->callback );

    // Remove the objects self reference
    luaL_unref( L, LUA_REGISTRYINDEX, obj->self );

    return 0;
}


// Called by the Lua garbage collector
static int gc_collect( lua_State *L ) {
    // Do cleanup stuff
    return 0;
}

// Called from C to call the Lua callback function for an object
static void do_callback( lua_State *L, Object *obj ) {
    // Push the callback function onto the stack
    lua_rawgeti( L, LUA_REGISTRYINDEX, obj->callback );

    // Push the args onto the stack
    lua_rawgeti( L, LUA_REGISTRYINDEX, obj->self );

    // Call the function
    lua_call( L, 1, 0 );
}

Each object shares a metatable for various methods, and a __gc callback for the garbage collector; nothing unusual there. The main loop in C runs, calls any Lua callbacks required by the objects and all works well. My grief is the deletion of the object when it is no longer required: In Lua:

-- Setup
obj = Object:new()
obj:set_callback( some_lua_function )

-- Elsewhere, some time later
obj:delete() -- required to remove the self reference
obj = nil

I have to call both 'obj:delete()' and 'obj = nil' for the GC to release the resources. Is there a way for the delete() function to nil any Lua variables that reference the userdata object? Some other solution would be most welcome!
DrTwox
DrTwox
A solution was suggested elsewhere: Store the 'self' reference in a weak table and the delete() method is no long required!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.