c++ 對象註冊到lua 內存管理 tolua_cclass 中的內存釋放 記一次閃退bug查找 此次閃退 可能發生在任何時機 難以查找

首先要了解lua的垃圾回收機制,lua中的垃圾回收機制是每隔一段時間清除不再被引用的對象,也就是說一個對象如果不再被使用就會在下次的gc中被回收掉,這個不需要我們管理,是lua中的自動回收機制。接下來看一下c++註冊到lua的接口:

TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col)

{

    char cname[128] = "const ";

    char cbase[128] = "const ";

    strncat(cname,name,120);

    strncat(cbase,base,120);

 

    mapinheritance(L,name,base);

    mapinheritance(L,cname,name);

 

    mapsuper(L,cname,cbase);

    mapsuper(L,name,base);

 

    lua_pushstring(L,lname);

    push_collector(L, name, col);

    /*

    luaL_getmetatable(L,name);

    lua_pushstring(L,".collector");

    lua_pushcfunction(L,col);

 

    lua_rawset(L,-3);

    */

 

//---- create a new class table, set it's metatable, and assign it to module

    lua_newtable(L);                    // stack: module lname table

    luaL_getmetatable(L,name);          // stack: module lname table mt

    lua_setmetatable(L, -2);            // stack: module lname table

    //Use a key named ".isclass" to be a flag of class_table

    lua_pushliteral(L, ".isclass");

    lua_pushboolean(L, 1);

    lua_rawset(L, -3);                  // stack: module lname table

    lua_rawset(L, -3);                  // stack: module

//---- by SunLightJuly, 2014.6.5

 

    /* now we also need to store the collector table for the const

       instances of the class */

    push_collector(L, cname, col);

    /*

    luaL_getmetatable(L,cname);

    lua_pushstring(L,".collector");

    lua_pushcfunction(L,col);

    lua_rawset(L,-3);

    lua_pop(L,1);

    */

}

 

在c++對象註冊到lua時一共有五個參數,這裏主要說明最後一個參數,在上邊的接口中第六行的函數實現如下:

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");

    /*

    if (!col) {

        lua_pushvalue(L, -1);

        lua_rawget(L, -3);

        if (!lua_isnil(L, -1)) {

            lua_pop(L, 3);

            return;

        };

        lua_pop(L, 1);

    };

    //    */

    lua_pushcfunction(L,col);

 

    lua_rawset(L,-3);

    lua_pop(L, 1);

};

lua中垃圾回收是在程序發生gc的時候,class_gc_event函數會去在lua對象的元表裏面找".collector"這個key,如果沒找到,就用default的析構,否則就用用戶提供的析構函數。也就是這一段代碼把最後的那個參數。此類對象則不需要用戶自己再去管理內存的釋放。否則若用戶先釋放了該對象,在gc中再次釋放的時候便會報錯。因爲gc發生的時機可能在每一個時間,所以就會出現程序一直閃退,但是每次閃退的點都不一樣,導致bug無法定位。所以要注意不要去管理此類對象的內存釋放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章