Sign in to follow this  
DrTwox

Circular references and garbage collection in LUA

Recommended Posts

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!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this