Garbage collection in tolua + +

Posted by newbreed65 on Thu, 17 Feb 2022 22:16:09 +0100

I want to know how the functions exported by tolua + + implement garbage collection and how to use meta methods__ On the gc Association.


  • gc of lua
    Looking at the code, the keyword used is ". collector", while lua's gc is through modifying the meta method__ gc implemented
Garbage userdata with a field __gc in their metatables are not collected immediately by the garbage collector. Instead, Lua puts them in a list. After the collection, Lua does the equivalent of the following function for each userdata in that list:

     function gc_event (udata)
       local h = metatable(udata).__gc
       if h then
  • gc related code in tolua + +
    Tolua is used_ register_ GC, put the object pointer in the "tolua_gc" table
/* Do clone
TOLUA_API int tolua_register_gc(lua_State* L, int lo)
    int success = 1;
    void* value = *(void**)lua_touserdata(L, lo);
    lua_pushstring(L, "tolua_gc");
    lua_rawget(L, LUA_REGISTRYINDEX);
    lua_pushlightuserdata(L, value);
    lua_rawget(L, -2);
    if (!lua_isnil(L, -1)) /* make sure that object is not already owned */
        success = 0;
        lua_pushlightuserdata(L, value);
        lua_getmetatable(L, lo);
        lua_rawset(L, -4);
    lua_pop(L, 2);
    return success;

So how?

Dispel doubts


First, when tolua + + is exported, various tables will be exported, including our relational tolua_gc.

  • tolua_open creates a closure, which uses tolua_gc this table
        /* create gc_event closure */
        lua_pushstring(L, "tolua_gc_event");
        lua_pushstring(L, "tolua_gc");
        lua_rawget(L, LUA_REGISTRYINDEX);
        lua_pushstring(L, "tolua_super");
        lua_rawget(L, LUA_REGISTRYINDEX);
        lua_pushcclosure(L, class_gc_event, 2);
        lua_rawset(L, LUA_REGISTRYINDEX);


This code can be understood by looking at it. It is called collector function

TOLUA_API int class_gc_event (lua_State* L)
    void* u = *((void**)lua_touserdata(L,1));
    int top;
    lua_pushvalue(L, lua_upvalueindex(1));
    lua_rawget(L,-2);            /* stack: gc umt    */
    lua_getmetatable(L,1);       /* stack: gc umt mt */
    /*fprintf(stderr, "checking type\n");*/
    top = lua_gettop(L);
    if (tolua_fast_isa(L,top,top-1, lua_upvalueindex(2))) /* make sure we collect correct type */
        /*fprintf(stderr, "Found type!\n");*/
        /* get gc function */
        lua_rawget(L,-2);           /* stack: gc umt mt collector */
        if (lua_isfunction(L,-1)) {
            /*fprintf(stderr, "Found .collector!\n");*/
        else {
            /*fprintf(stderr, "Using default cleanup\n");*/
        lua_pushvalue(L,1);         /* stack: gc umt mt collector u */
        lua_pushlightuserdata(L,u); /* stack: gc umt mt u */
        lua_pushnil(L);             /* stack: gc umt mt u nil */
        lua_rawset(L,-5);           /* stack: gc umt mt */
    return 0;

This function does two things
(1) First from tolua_ Take the GC table and call it. Memory release by collector
That is, the previous codes, where lua_upvalueindex(1) corresponds to tolua_gc table

    lua_pushvalue(L, lua_upvalueindex(1));
    lua_rawget(L,-2);            /* stack: gc umt    */
    lua_getmetatable(L,1);       /* stack: gc umt mt */

(2) If there is an inheritance relationship, you need to ensure that you get the correct pointer. Tolua is used here_ Super Table

Well, this How did collector come about?

. collector registration

  • tolua_cclass
    Use tolua_cclass register gc function
// register
// gc function
static int tolua_collect_KVec3 (lua_State* tolua_S)
 KVec3* self = (KVec3*) tolua_tousertype(tolua_S,1,0);
    return 0;
  • push_collector
    tolua_ Push will be called in Cclass_ The collector function is to The collector function is registered in the meta table of the class name (KVec3, etc.)
static void push_collector(lua_State* L, const char* type, lua_CFunction col) {
    /* push collector function, but only if it's not NULL, or if there's no
       collector already */
    if (!col) return;
    luaL_getmetatable(L, type);
    lua_pushstring(L, ".collector");

    lua_pushcfunction(L, col);
    lua_rawset(L, -3);
    lua_pop(L, 1);

Just look now__ gc and this How are collector s associated


tolua_ Tolua will be called in open_ Newmetatable method, where tolua is called_ Classevents function

tolua_newmetatable(L, "tolua_commonclass");
  • tolua_classevents
    This function is binding__ Of gc meta methods
    lua_pushstring(L, "tolua_gc_event");
    lua_rawget(L, LUA_REGISTRYINDEX);

The code is very clear. The meta method is tolua_gc_event, which is the same as tolua in the front_ The closure registered in open is connected


Summarize the ideas of these places

  • 1. Register a closure at the beginning, including a tolua_gc table, which is used to store c + + object pointers
  • 2. Each time a local object is created, the c + + pointer will be placed in this tolua_ In the table of GC, by calling tolua_register_gc method registration.
  • 3. Every time after the object GC of lua, the object registration will be called__ GC meta method, this meta method class_gc_event is a closure
  • 4. There are two upvalue values in this closure, tolua_gc and tolua_super. tolua_super in tolua_fast_isa will be used. Because inheritance is implemented, it is mainly to find the correct object
  • 5. When will tolua be used_ What about GC? If the c + + object does not call tolua_ register_ Register GC with tolua_ In the GC table. Even if every time the lua object GC triggers a call to class_ gc_ In event closure The collector function is also not released from tolua_ There is no object to delete in GC

Topics: lua tools