I want to know how the functions exported by tolua + + implement garbage collection and how to use meta methods__ On the gc Association.
doubt
- 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 h(udata) end end Source: http://www.lua.org/manual/5.1/manual.html#2.10.1
- 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; else { lua_pushlightuserdata(L, value); lua_getmetatable(L, lo); lua_rawset(L, -4); } lua_pop(L, 2); return success; }
So how?
Dispel doubts
tolua_gc
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);
class_gc_event
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_pushlightuserdata(L,u); 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_pushliteral(L,".collector"); lua_rawget(L,-2); /* stack: gc umt mt collector */ if (lua_isfunction(L,-1)) { /*fprintf(stderr, "Found .collector!\n");*/ } else { lua_pop(L,1); /*fprintf(stderr, "Using default cleanup\n");*/ lua_pushcfunction(L,tolua_default_collect); } lua_pushvalue(L,1); /* stack: gc umt mt collector u */ lua_call(L,1,0); 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 */ } lua_pop(L,3); 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_pushlightuserdata(L,u); 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 tolua_cclass(tolua_S,"KVec3","KVec3","",tolua_collect_KVec3); // gc function static int tolua_collect_KVec3 (lua_State* tolua_S) { KVec3* self = (KVec3*) tolua_tousertype(tolua_S,1,0); Mtolua_delete(self); 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_classevents
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,"__gc"); lua_pushstring(L, "tolua_gc_event"); lua_rawget(L, LUA_REGISTRYINDEX); /*lua_pushcfunction(L,class_gc_event);*/ lua_rawset(L,-3);
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
summary
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