lua 5.3.4 GC的变化-UpVal变为引用计数管理
2017-09-29 本文已影响72人
云木unity
Lua 5.1.4
/*
** Upvalues
*/
typedef struct UpVal {
CommonHeader;
TValue *v; /* points to stack or to its own value */
union {
TValue value; /* the value (when closed) */
struct { /* double linked list (when open) */
struct UpVal *prev;
struct UpVal *next;
} l;
} u;
} UpVal;
/*
** `global state', shared by all threads of this state
*/
typedef struct global_State {
...
UpVal uvhead; /* head of double-linked list of all open upvalues */
...
} global_State;
/*
** `per thread' state
*/
struct lua_State {
...
GCObject *openupval; /* list of open upvalues in this stack */
...
};
Lua 5.3.4
/*
** Upvalues for Lua closures
*/
struct UpVal {
TValue *v; /* points to stack or to its own value */
lu_mem refcount; /* reference counter */
union {
struct { /* (when open) */
UpVal *next; /* linked list */
int touched; /* mark to avoid cycles with dead threads */
} open;
TValue value; /* the value (when closed) */
} u;
};
/*
** 'global state', shared by all threads of this state
*/
typedef struct global_State {
...
struct lua_State *twups; /* list of threads with open upvalues */
...
} global_State;
/*
** `per thread' state
*/
struct lua_State {
...
UpVal *openupval; /* list of open upvalues in this stack */
struct lua_State *twups; /* list of threads with open upvalues */
...
};
UpVal 要注意的是:
-
UpVal 结构中去掉了 GCObject 的通用 hader (CommonHeader),增加了一个引用计数器[refcount];
使得 UpVal 对象不再作为 GC 对象被虚拟机的 标记-清除 GC 所管理,而是成为单独使用引用计数的方法管理的小内存块
-
支持双向链表的两个指针 [prev] [next] ,改为了一个指针 [next] 加上一个 [touched] 标记
-
去掉了g->uvhead双向链表,只留下L->openupval,并且openupval链表的类型从GCObject改为UpVal (不受标记-清除 GC 所管理)
-
函数执行完毕时,从 L->openupval 中去除,不再挂到`gcroot' list;
在 free closure 对象时(freeLclosure函数),对 closure 对象 upvals 列表中的所有 UpVal 对象执行引用计数减1操作,以此来管理 UpVal 的生命周期
Lua ==5.1.4== ++luaF_close++:
void luaF_close (lua_State *L, StkId level) {
UpVal *uv;
...
while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
GCObject *o = obj2gco(uv);
...
L->openupval = uv->next; /* remove from `open' list */
if (isdead(g, o))
luaF_freeupval(L, uv); /* free upvalue */
else {
unlinkupval(uv);
setobj(L, &uv->u.value, uv->v);
uv->v = &uv->u.value; /* now current value lives here */
luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */
}
}
}
Lua ==5.3.4== ++luaF_close++、++freeLclosure++:
void luaF_close (lua_State *L, StkId level) {
UpVal *uv;
while (L->openupval != NULL && (uv = L->openupval)->v >= level) {
lua_assert(upisopen(uv));
L->openupval = uv->u.open.next; /* remove from 'open' list */
if (uv->refcount == 0) /* no references? */
luaM_free(L, uv); /* free upvalue */
else {
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
luaC_upvalbarrier(L, uv);
}
}
}
static void freeLclosure (lua_State *L, LClosure *cl) {
int i;
for (i = 0; i < cl->nupvalues; i++) {
UpVal *uv = cl->upvals[i];
if (uv)
luaC_upvdeccount(L, uv);-- 引用计数减1
}
luaM_freemem(L, cl, sizeLclosure(cl->nupvalues));
}
-- 引用计数减1,若为0则luaM_free
void luaC_upvdeccount (lua_State *L, UpVal *uv) {
lua_assert(uv->refcount > 0);
uv->refcount--;
if (uv->refcount == 0 && !upisopen(uv))
luaM_free(L, uv);
}
-
global_State中增加了一个 twups 链表 /* list of threads with open upvalues */
所有带有 open upvalue 的 thread 都会放到这个链表中,这样提供了一个方便的遍历 thread 的途径,并且排除掉了没有 open upvalue 的 thread
参考: