diff options
Diffstat (limited to 'src/lua51/lgc.c')
| -rw-r--r-- | src/lua51/lgc.c | 286 |
1 files changed, 198 insertions, 88 deletions
diff --git a/src/lua51/lgc.c b/src/lua51/lgc.c index ae845e9..afebe04 100644 --- a/src/lua51/lgc.c +++ b/src/lua51/lgc.c @@ -48,15 +48,18 @@ #define VALUEWEAK bitmask(VALUEWEAKBIT) -// 标记对象,有点类似一个安全声明,mark了的对象不会被回收,会被标记为灰色(大多数情况下)或黑色 +// markvalue和markobject不同之处在于类型不同,一个接受TValue*类型,一个接受任意合理的指针类型 + +// 标记值为灰色 #define markvalue(g,o) { checkconsistency(o); \ if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } +// 标记对象为灰色 #define markobject(g,t) { if (iswhite(obj2gco(t))) \ reallymarkobject(g, obj2gco(t)); } -// 手动GC +// 设置GC阈值 // estimate 使用中的内存大小估值 // gcpause 控制两次GC间隔的百分数 #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) @@ -69,37 +72,52 @@ static void removeentry (Node *n) { } -//c 标记object(不标记这个object引用的object,udata除外,需要标记udata的mt和env) -//c 至于标记object引用的object留在扫描阶段 +//c 扫描标记object为灰色(不标记这个object引用的object,udata除外,需要标记udata的mt和env) +//c 至于标记object引用的object留在扫描阶段,这样做是为了缩短时间 static void reallymarkobject (global_State *g, GCObject *o) { lua_assert(iswhite(o) && !isdead(g, o)); - //改为灰色 + + //标记为灰色 white2gray(o); - //对于大部分类型,都是把gcobject加到gray链表 + switch (o->gch.tt) { case LUA_TSTRING: { // 字符串不会引用其他数据,所以略过,不用加到gray list return; } + case LUA_TUSERDATA: { - // udata本身也不会引用其他对象,所以不需要扫描,直接标记为黑色 + // udata本身也不会引用其他对象(除了元表和环境表),所以不需要扫描,直接标记为黑色 Table *mt = gco2u(o)->metatable; // 直接标记为黑色 gray2black(o); /* udata are never gray */ - // 标记一下它的mt和env表 + // 顺便标记一下它的元表和env表,userdata只会引用元表和环境表 if (mt) markobject(g, mt); markobject(g, gco2u(o)->env); return; } + case LUA_TUPVAL: { - UpVal *uv = gco2uv(o); + log("reallymarkobject().LUA_TUPVAL"); + UpVal *uv = gco2uv(o); + // 把upvalue引用的对象标记为灰色 markvalue(g, uv->v); - // 当这个upvalue是closed状态,表示这个uv已经没有与其他数据的引用关系 - // 直接标记黑色 - if (uv->v == &uv->u.value) /* closed? */ - gray2black(o); /* open upvalues are never black */ + // 如果这个upvalue是closed状态,表示这个uv已经没有与其他数据的引用关系 + // 直接把upvalue标记为黑色,upvalue自己保存这个变量 + if (uv->v == &uv->u.value) /* closed? */ + { + log("closed upvalue"); + gray2black(o); /* open upvalues are never black */ + } + // open的upvalue永远不会是黑色的(因为没有意义),需要持续检查,在remarkupvals()函数 + // open upvalue不在gray链中维护,而在global_State的uvhead,等到atomic()的时候再mark + // 所以这里没有把open upvalue放入灰链 + // 参见remarkupvals() return; } + + // 对于 function, table, thread, proto, 将它们加入gray链 + case LUA_TFUNCTION: { gco2cl(o)->c.gclist = g->gray; g->gray = o; @@ -124,29 +142,35 @@ static void reallymarkobject (global_State *g, GCObject *o) { } } - +// 将g->tmudata链中的udata标记为灰色 static void marktmu (global_State *g) { GCObject *u = g->tmudata; if (u) { do { u = u->gch.next; + + // 将这个udata标记为灰色 makewhite(g, u); /* may be marked, if left from previous GC */ reallymarkobject(g, u); + } while (u != g->tmudata); } } -//c 处理 userdata,userdata都在atomic里面处理,而不是propagatemark -//c userdata都跟在mainthread之后(这是一个hack的做法,统一放在一个地方,方便处理) +//c 将需要调用__gc和不需要的udata分开 +// 处理 userdata,userdata都在atomic里面处理,而不是propagatemark +// userdata都跟在mainthread之后(这是一个hack的做法,统一放在一个地方,方便处理) /* move `dead' udata that need finalization to list `tmudata' */ size_t luaC_separateudata (lua_State *L, int all) { global_State *g = G(L); size_t deadmem = 0; + // udata的链表 GCObject **p = &g->mainthread->next; GCObject *curr; + while ((curr = *p) != NULL) /*遍历*/{ - //udata创建的时候是白色,加载mainthread后面 + //userdata创建的时候是白色,加在mainthread后面 if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) // 如果该udata不需要回收,跳过 p = &curr->gch.next; /* don't bother with them */ else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { // 如果没注册__gc @@ -154,7 +178,7 @@ size_t luaC_separateudata (lua_State *L, int all) { markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } - else { /* must call its gc method */ + else { /* must call its gc method */ // 加入G(L)->tmudata链 deadmem += sizeudata(gco2u(curr)); // 标记为finalized后,还需要加入G(L)->tmudata链表 markfinalized(gco2u(curr)); @@ -187,7 +211,8 @@ static int traversetable (global_State *g, Table *h) { if (mode && ttisstring(mode)) { /* is there a weak mode? */ weakkey = (strchr(svalue(mode), 'k') != NULL); weakvalue = (strchr(svalue(mode), 'v') != NULL); - if (weakkey || weakvalue) { /* is really weak? */ + if (weakkey || weakvalue) { /* is really weak? */ + // 如果是弱表,加到g->weak链表,在扫描的第二阶段atomic处理 h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast_byte((weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); @@ -196,9 +221,11 @@ static int traversetable (global_State *g, Table *h) { g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } - if (weakkey && weakvalue) return 1; // 如果是弱表,返回1 - // 如果不是弱表,遍历table的散列部分和数组部分所有元素 + if (weakkey && weakvalue) + return 1; // 如果是弱表,返回1,从black置回gray以备atomic重新扫描 + + // 如果不是弱表,遍历table的散列部分和数组部分所有元素并标记,加入灰链 //数组 if (!weakvalue) { @@ -220,6 +247,7 @@ static int traversetable (global_State *g, Table *h) { if (!weakvalue) markvalue(g, gval(n)); } } + return weakkey || weakvalue; } @@ -236,7 +264,7 @@ static void traverseproto (global_State *g, Proto *f) { // 标记常量 for (i=0; i<f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); - // 标记upvalue + // 标记upvalue名 for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ if (f->upvalues[i]) stringmark(f->upvalues[i]); @@ -254,11 +282,13 @@ static void traverseproto (global_State *g, Proto *f) { } - +// 遍历闭包,标记env, proto, upvalue为灰色,加入灰链 static void traverseclosure (global_State *g, Closure *cl) { markobject(g, cl->c.env); + if (cl->c.isC) { int i; + // 标记upvalue for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->c.upvalue[i]); } @@ -266,6 +296,7 @@ static void traverseclosure (global_State *g, Closure *cl) { int i; lua_assert(cl->l.nupvalues == cl->l.p->nups); markobject(g, cl->l.p); + // 标记upvalue for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ markobject(g, cl->l.upvals[i]); } @@ -304,20 +335,32 @@ static void traversestack (global_State *g, lua_State *l) { } -//c 扫描和标记操作入口 /* ** traverse one gray object, turning it to black. ** Returns `quantity' traversed. */ +//c 将对象从灰->黑并从灰色链删除,表示这个对象以及所引用的对象都已经标记过 +// 只遍历*一个*灰色对象,增量地把对象分布到不同的step中(因为遍历对象的引用是非常慢的) +// 和reallymarkobject的区别在后者不会标记所引用的对象(除了userdata),而这个会调用 +// traverse*()进行标记,采用广度优先 static l_mem propagatemark (global_State *g) { - GCObject *o = g->gray; + GCObject *o = g->gray; // 拿到gray的第一个,只处理这一个 lua_assert(isgray(o)); - gray2black(o);//预先标记为黑色 - //只有table、function、thread、proto会引用其他对象 + + gray2black(o);//预先标记为黑色,对于特殊的四个类型需要递归它引用的对象 + +//下面四个语句将对象o排除出gray链即这个对象已经被标记为了黑色,且被引用对象也遍历过了 +//g->gray = h->gclist; +//g->gray = cl->c.gclist; +//g->gray = th->gclist; +//g->gray = p->gclist; + + //只有 table、function、thread、proto 会引用其他对象,需要递归遍历他们引用的对象 + //刚开始进入GCSpropagate阶段时会遍历lua_State, global table, register table switch (o->gch.tt) { case LUA_TTABLE: { //扫描table,尝试标记数组和哈希部分 Table *h = gco2h(o); - g->gray = h->gclist; + g->gray = h->gclist; // 如果是弱表,回退回灰色状态 if (traversetable(g, h)) /* table is weak? */ black2gray(o); /* keep it gray */ @@ -333,12 +376,13 @@ static l_mem propagatemark (global_State *g) { } case LUA_TTHREAD: { //扫描线程对象, 因为lua_State关联的数据变化频繁,所以从graylist中拿出来放到grayaginlist中 lua_State *th = gco2th(o); + // 将lua_state从gray中删除,加到grayagain里 - g->gray = th->gclist; - th->gclist = g->grayagain; + g->gray = th->gclist; // 从gray链删除 + th->gclist = g->grayagain; // 加入grayagin链 g->grayagain = o; - // 颜色退回为灰色 - black2gray(o); + black2gray(o);// 颜色退回为灰色,便于在后续grayagin处理 + traversestack(g, th); return sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->size_ci; @@ -354,7 +398,7 @@ static l_mem propagatemark (global_State *g) { sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; } - default: + default: // 其余类型不会引用其他对象 lua_assert(0); return 0; } @@ -416,6 +460,7 @@ static void cleartable (GCObject *l) { } +//c 释放对象内存 static void freeobj (lua_State *L, GCObject *o) { switch (o->gch.tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; @@ -445,7 +490,9 @@ static void freeobj (lua_State *L, GCObject *o) { //c p刚进来是这个散列桶的第一个字符串 #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) - +//c 回收 count 个(字符串)链表 +// p是在rootgc链上的位置 +// count 每次回收的对象个数 static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; global_State *g = G(L); @@ -456,12 +503,12 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { sweepwholelist(L, &gco2th(curr)->openupval); if ((curr->gch.marked ^ WHITEBITS) & deadmask) { /* not dead? */ lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT)); - makewhite(g, curr); /* make it white (for next cycle) */ - p = &curr->gch.next; + makewhite(g, curr); /* make it white (for next cycle) */ // 重新标记为白色,等待下次GC + p = &curr->gch.next; // } else { /* must erase `curr' */ lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); - *p = curr->gch.next; + *p = curr->gch.next; // 将这个对象从rootgc中删除 if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ //c! 回收对象,根据类型调用不同的内存释放方法 @@ -473,12 +520,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { //c 检查字符串桶的大小,如果太大了,将空的桶删掉,重新分配桶 -//c static void checkSizes (lua_State *L) { global_State *g = G(L); /* check size of string hash */ - //c 如果桶的总大小是用到的桶位(即字符串数量)的4倍,且是MINSTRTABSIZE的2倍 - //c 给桶瘦身 + // 如果桶的总大小是用到的桶位(即字符串数量)的4倍,且是MINSTRTABSIZE的2倍 + // 给桶瘦身 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && g->strt.size > MINSTRTABSIZE*2) luaS_resize(L, g->strt.size/2); /* table is too big */ @@ -550,46 +596,53 @@ static void markmt (global_State *g) { } -//c 初始化root -//c 将mainthread, +//c GC初始化,根查找阶段,一步完成 +//c 将mainthread /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); - // 清空 + + // 1. 清空链表准备这次GC流程 g->gray = NULL; g->grayagain = NULL; g->weak = NULL; - // 标记mainthread + + // 2. 标记mainthread、全局表、注册表为灰色并加入链表gray + // 从这几个开始在扫描阶段将它们引用的对象依次遍历 markobject(g, g->mainthread); - /* make global table be traversed before main stack */ - // 标记 _G 为灰色 - markvalue(g, gt(g->mainthread)); - // 标记注册表为灰色 + markvalue(g, gt(g->mainthread));/* make global table be traversed before main stack */ markvalue(g, registry(L)); - markmt(g); + markmt(g); /*基本类型的元方法*/ + //GC 切换到扫描阶段 g->gcstate = GCSpropagate; } +//c 扫描open状态的upvalue,之所以在 static void remarkupvals (global_State *g) { UpVal *uv; for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) { lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv); - if (isgray(obj2gco(uv))) + if (isgray(obj2gco(uv))) // 在reallymarkobject的LUA_TUPVAL处理,对于open的upvalue会标记为灰色,等到这里处理 markvalue(g, uv->v); } } -//c 原子化处理grayagain +//c 原子化一步扫描剩余的部分 +// 1. open状态的upvalue +// 2. weak表内容、当前的lua_State、基本类型的元表 +// 3. grayagin链 +// 4. userdata static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ - /* remark occasional upvalues of (maybe) dead threads */ - remarkupvals(g); - /* traverse objects cautch by write barrier and by 'remarkupvals' */ - propagateall(g); + + //扫描open状态的upvalue + remarkupvals(g);/* remark occasional upvalues of (maybe) dead threads */ // 这个调用之后gray链上会有新的内容(upvalue引用的对象),所以还需要调用下一个函数 + propagateall(g);/* traverse objects cautch by write barrier and by 'remarkupvals' */ + /* remark weak tables */ g->gray = g->weak; g->weak = NULL; @@ -597,44 +650,61 @@ static void atomic (lua_State *L) { markobject(g, L); /* mark running thread */ markmt(g); /* mark basic metatables (again) */ propagateall(g); + /* remark gray again */ g->gray = g->grayagain; g->grayagain = NULL; propagateall(g); - // 处理udata - udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ - marktmu(g); /* mark `preserved' userdata */ + + // 处理userdata + udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ // 将需要调用__gc和不需要的udata分开 + marktmu(g); /* mark `preserved' userdata */ // 将tmudata链里的udata标记为灰色并加入gray链 udsize += propagateall(g); /* remark, to propagate `preserveness' */ + cleartable(g->weak); /* remove collected objects from weak tables */ - /* flip current white */ - g->currentwhite = cast_byte(otherwhite(g)); + + // 结束atomic + g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ g->sweepstrgc = 0; - // 设置当前清理的位置 - g->sweepgc = &g->rootgc; - // 切换到回收字符串阶段 - g->gcstate = GCSsweepstring; + g->sweepgc = &g->rootgc;// 标记当前回收到的位置在rootgc中的位置 + g->gcstate = GCSsweepstring; // 切换到回收字符串阶段 g->estimate = g->totalbytes - udsize; /* first estimate */ } -//c! 单步GC的入口 +//c! GC的入口,会根据当前GC的状态进不同的流程 static l_mem singlestep (lua_State *L) { global_State *g = G(L); /*lua_checkmemory(L);*/ +/* 分为几大步执行 + 1. GCSpause 初始化 + 2. GCSpropagate 扫描 + gray + grayagain + 3. GCSsweepstring 回收字符串 + 4. GCSsweep 回收其他类型 + 5. GCSfinalize 结束 +*/ switch (g->gcstate) { - case GCSpause: { // 初始化 + case GCSpause: { // 初始化,原子操作 markroot(L); /* start a new collection */ return 0; } + case GCSpropagate: { // 扫描并标记 - if (g->gray) // gray list不为空 - return propagatemark(g); + //总的分两步,先按照一定的粒度逐个遍历gray链,然后原子化处理grayagin链表 + if (g->gray) // 如果gray没处理完,处理gray链 + //1.遍历gray链表标记所有数据和引用的数据,有些数据被加入grayagain链表,比如thread + return propagatemark(g); //遍历一个 else { /* no more `gray' objects */ + //2.使用atomic函数遍历grayagin atomic(L); /* finish mark phase */ return 0; } } + case GCSsweepstring: { // 回收字符串 + // 每次回收一个字符串链表 lu_mem old = g->totalbytes; // 回收g->sweepstrgc位置的散列桶 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); @@ -644,8 +714,10 @@ static l_mem singlestep (lua_State *L) { g->estimate -= old - g->totalbytes; return GCSWEEPCOST; } + case GCSsweep: { // 回收字符串以外的其他类型 lu_mem old = g->totalbytes; + // 回收 GCSWEEPMAX 个对象 g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); if (*g->sweepgc == NULL) { /* nothing more to sweep? */ checkSizes(L); @@ -655,9 +727,11 @@ static l_mem singlestep (lua_State *L) { g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } + case GCSfinalize: { // 结束阶段,专门处理 tmudata ,调用userdata的__gc方法,释放native引用 + // 每次处理一个udata if (g->tmudata) { - GCTM(L); + GCTM(L); //调用__gc方法 if (g->estimate > GCFINALIZECOST) g->estimate -= GCFINALIZECOST; return GCFINALIZECOST; @@ -669,6 +743,7 @@ static l_mem singlestep (lua_State *L) { return 0; } } + default: lua_assert(0); return 0; } } @@ -677,7 +752,7 @@ static l_mem singlestep (lua_State *L) { //c! GC 入口 void luaC_step (lua_State *L) { global_State *g = G(L); - l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; + l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; // 本次回收计划回收的内存大小,会影响每次gc执行singlestep的次数 if (lim == 0) lim = (MAX_LUMEM-1)/2; /* no limit */ g->gcdept += g->totalbytes - g->GCthreshold; @@ -699,8 +774,9 @@ void luaC_step (lua_State *L) { } } - +//c STW(stop-the-world) GC,一次性清理GC void luaC_fullgc (lua_State *L) { + log("luaC_fullgc"); global_State *g = G(L); if (g->gcstate <= GCSpropagate) { /* reset sweep marks to sweep all elements (returning them to white) */ @@ -725,62 +801,96 @@ void luaC_fullgc (lua_State *L) { setthreshold(g); } +//屏障是为了应对在“扫描”阶段新建对象时的情况 -//c 向前避障 +//c 向前屏障,指新建的数据从白色->灰色加入灰色链 +// o 黑 v 白 +// 在lgc.h里面定义的几个宏会限定barrier操作不会发生在GCSpause和GCSfinalize阶段,这两个阶段不需要屏蔽操作,正常处理即可 void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); + lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); - lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + // GCSfinalize下不会有黑色对象和GCSpause下不会有白色对象 + lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); lua_assert(ttype(&o->gch) != LUA_TTABLE); + /* must keep invariant? */ if (g->gcstate == GCSpropagate)// 如果在扫描阶段,把新建的v加入gray链 reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ // 否则标记为白色,等待下一次GC + else /* don't mind */ // 如果在清除阶段,正常处理,标记为当前白,等待下一次GC makewhite(g, o); /* mark as white just to avoid other barriers */ } -//c 向后避障只作用于 table,将table加入 grayagain 链表 +//c 向后屏障只作用于 table,将table从黑色变灰加入*grayagain*链表(而不是gray链表) +// 指新建数据的引用者从黑色->灰色 +// 之所以table采用向后屏障,而不是向前屏障,将table重新设为灰色并加入*grayagin*在atomic处理 +// 是由于table的1对N特点,避免多次新建项导致的不必要消耗,同时加入grayagin而不是gray,是为了 +// 避免一个对象频繁的“被退回-扫描-回退-扫描”过程,在扫描步骤中一旦这个表被修改了且已经标为了黑 +// 色, 直接把它加到grayagin里处理,而不是像其他类型处理一样使用向前屏障 void luaC_barrierback (lua_State *L, Table *t) { global_State *g = G(L); GCObject *o = obj2gco(t); + lua_assert(isblack(o) && !isdead(g, o)); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); + black2gray(o); /* make table gray (again) */ - // 加到grayagin list里 + + // 加到grayagin链 t->gclist = g->grayagain; g->grayagain = o; } -//c! 将一个新建的GCGamobject(udata除外,加载其他地方,具体看luaS_newudata)加入root,并标记为白色 -//c upvalue 不一定会设为white,所以不会调这个函数 -//c 虽然被加入了rootgc,但是不会被轻易回收,lua有双白色缓冲概念 -//c 分为currentwhite和otherwhite。如果某个对象创建在GC的标记阶段以后,它的white和标记时的white不是一个white, -//c 在回收阶段会判断一下,不会回收这个对象 -//c global_State的currentwhite switch发生在标记阶段后 +//c! luaC_link和luaC_linkupval 函数用于创建对象时调用加入gc链 + + +//c! 将一个新建的GCGamobject:function, table, thread(udata除外,加载其他地方,具体看luaS_newudata) +// 加入rootgc,并标记为白色 +// upvalue 不一定会设为white,所以不会调这个函数 +// 虽然被加入了rootgc,但是不会被轻易回收,lua有双白色缓冲概念 +// 分为currentwhite和otherwhite。如果某个对象创建在GC的标记阶段以后,它的white和标记时的white不是一个white, +// 在回收阶段会判断一下,不会回收这个对象 +// global_State的currentwhite switch发生在标记阶段后 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { +//log("luaC_link()"); global_State *g = G(L); + + // 将这个新建对象加入rootgc链 o->gch.next = g->rootgc; g->rootgc = o; - o->gch.marked = luaC_white(g);//标记为current white + + o->gch.marked = luaC_white(g);//标记为当前白 o->gch.tt = tt;//设置数据类型 } //c! 将一个upvalue加入root,由于upvalue是对已经存在的对象的间接引用,所以和普通对象不太一样 void luaC_linkupval (lua_State *L, UpVal *uv) { + log("luaC_linkupval()"); + + // 进这个函数里的upvalue都是close upvalue + global_State *g = G(L); - GCObject *o = obj2gco(uv); + GCObject *o = obj2gco(uv); // 这个o是 + + // 将这个upvalue加入rootgc链 o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; + // 这里和普通对象不一样 - if (isgray(o)) { - if (g->gcstate == GCSpropagate) {//如果在扫描阶段,直接将对象置为黑色 - gray2black(o); /* closed upvalues need barrier */ - luaC_barrier(L, uv, uv->v); + if (isgray(o)) { // 在扫描阶段realymarkobject标记为了灰色, + if (g->gcstate == GCSpropagate) {//如果在扫描阶段,直接标记为黑色 + log("GCSpropagate"); + gray2black(o); /* closed upvalues need barrier */ + luaC_barrier(L, uv, uv->v); +/* if(valiswhite(uv->v) && isblack(obj2go(uv))) + luaC_barrierf(L,obj2gco(uv),gcvalue(uv->v)); +*/ } else { /* 否则的话和普通对象一样置为白色 */ /* sweep phase: sweep it (turning it into white) */ makewhite(g, o); + log("not GCSpropagate"); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); } } |
