diff options
Diffstat (limited to 'src/lua51/lgc.c')
| -rw-r--r-- | src/lua51/lgc.c | 82 |
1 files changed, 62 insertions, 20 deletions
diff --git a/src/lua51/lgc.c b/src/lua51/lgc.c index f4dbdfb..ae845e9 100644 --- a/src/lua51/lgc.c +++ b/src/lua51/lgc.c @@ -56,6 +56,9 @@ reallymarkobject(g, obj2gco(t)); } +// 手动GC +// estimate 使用中的内存大小估值 +// gcpause 控制两次GC间隔的百分数 #define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) @@ -133,28 +136,35 @@ static void marktmu (global_State *g) { } } - +//c 处理 userdata,userdata都在atomic里面处理,而不是propagatemark +//c 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) { - if (!(iswhite(curr) || all) || isfinalized(gco2u(curr))) + while ((curr = *p) != NULL) /*遍历*/{ + //udata创建的时候是白色,加载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) { + else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { // 如果没注册__gc + // 标记这个udata为finalized,不需要走finalization流程去调用__gc释放那些native引用 markfinalized(gco2u(curr)); /* don't need finalization */ p = &curr->gch.next; } else { /* must call its gc method */ deadmem += sizeudata(gco2u(curr)); + // 标记为finalized后,还需要加入G(L)->tmudata链表 markfinalized(gco2u(curr)); *p = curr->gch.next; + // 把这个udata加到 tmudata 链表最后 /* link `curr' at the end of `tmudata' list */ if (g->tmudata == NULL) /* list is empty? */ g->tmudata = curr->gch.next = curr; /* creates a circular list */ else { + //? 这里没看懂 curr->gch.next = g->tmudata->gch.next; g->tmudata->gch.next = curr; g->tmudata = curr; @@ -214,23 +224,29 @@ static int traversetable (global_State *g, Table *h) { } +// 扫描函数原型 /* ** All marks are conditional because a GC may happen while the ** prototype is still being created */ static void traverseproto (global_State *g, Proto *f) { int i; - if (f->source) stringmark(f->source); + // 标记文件名 + if (f->source) stringmark(f->source); + // 标记常量 for (i=0; i<f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); + // 标记upvalue for (i=0; i<f->sizeupvalues; i++) { /* mark upvalue names */ if (f->upvalues[i]) stringmark(f->upvalues[i]); } + // 标记内部定义的函数 for (i=0; i<f->sizep; i++) { /* mark nested protos */ if (f->p[i]) markobject(g, f->p[i]); } + // 标记局部变量 for (i=0; i<f->sizelocvars; i++) { /* mark local-variable names */ if (f->locvars[i].varname) stringmark(f->locvars[i].varname); @@ -288,6 +304,7 @@ static void traversestack (global_State *g, lua_State *l) { } +//c 扫描和标记操作入口 /* ** traverse one gray object, turning it to black. ** Returns `quantity' traversed. @@ -296,6 +313,7 @@ static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o);//预先标记为黑色 + //只有table、function、thread、proto会引用其他对象 switch (o->gch.tt) { case LUA_TTABLE: { //扫描table,尝试标记数组和哈希部分 Table *h = gco2h(o); @@ -313,20 +331,22 @@ static l_mem propagatemark (global_State *g) { return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues); } - case LUA_TTHREAD: { //扫描线程对象, + 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->grayagain = o; + // 颜色退回为灰色 black2gray(o); traversestack(g, th); return sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->size_ci; } - case LUA_TPROTO: { + case LUA_TPROTO: { //扫描函数原型,尝试标记文件名、字符串、upvalue、局部变量 Proto *p = gco2p(o); g->gray = p->gclist; - traverseproto(g, p); + traverseproto(g, p);//标记函数原型的文件名、字符串、upvalue、局部变量 return sizeof(Proto) + sizeof(Instruction) * p->sizecode + sizeof(Proto *) * p->sizep + sizeof(TValue) * p->sizek + @@ -334,7 +354,9 @@ static l_mem propagatemark (global_State *g) { sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues; } - default: lua_assert(0); return 0; + default: + lua_assert(0); + return 0; } } @@ -419,14 +441,16 @@ static void freeobj (lua_State *L, GCObject *o) { } - +//c 回收阶段回收字符串,每次回收g->strt中的一个桶 +//c p刚进来是这个散列桶的第一个字符串 #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { GCObject *curr; global_State *g = G(L); - int deadmask = otherwhite(g); + int deadmask = otherwhite(g); // 不可回收的白色,要回收的是currentwhite + // 遍历链表 while ((curr = *p) != NULL && count-- > 0) { if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ sweepwholelist(L, &gco2th(curr)->openupval); @@ -440,6 +464,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { *p = curr->gch.next; if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ + //c! 回收对象,根据类型调用不同的内存释放方法 freeobj(L, curr); } } @@ -465,6 +490,7 @@ static void checkSizes (lua_State *L) { } +//c 调用 __gc 方法,执行finalization,每次释放一个udata的native引用 static void GCTM (lua_State *L) { global_State *g = G(L); GCObject *o = g->tmudata->gch.next; /* get first element */ @@ -477,16 +503,20 @@ static void GCTM (lua_State *L) { g->tmudata->gch.next = udata->uv.next; udata->uv.next = g->mainthread->next; /* return it to `root' list */ g->mainthread->next = o; + //标记为白色,进入下一次GC的时候回收自身的内存 makewhite(g, o); + //调用 __gc tm = fasttm(L, udata->uv.metatable, TM_GC); if (tm != NULL) { lu_byte oldah = L->allowhook; lu_mem oldt = g->GCthreshold; L->allowhook = 0; /* stop debug hooks during GC tag method */ g->GCthreshold = 2*g->totalbytes; /* avoid GC steps */ + // 压入__gc和udata setobj2s(L, L->top, tm); setuvalue(L, L->top+1, udata); L->top += 2; + // 调用__gc luaD_call(L, L->top - 2, 0); L->allowhook = oldah; /* restore hooks */ g->GCthreshold = oldt; /* restore threshold */ @@ -537,6 +567,7 @@ static void markroot (lua_State *L) { // 标记注册表为灰色 markvalue(g, registry(L)); markmt(g); + //GC 切换到扫描阶段 g->gcstate = GCSpropagate; } @@ -551,6 +582,7 @@ static void remarkupvals (global_State *g) { } +//c 原子化处理grayagain static void atomic (lua_State *L) { global_State *g = G(L); size_t udsize; /* total size of userdata to be finalized */ @@ -569,6 +601,7 @@ static void atomic (lua_State *L) { 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 */ udsize += propagateall(g); /* remark, to propagate `preserveness' */ @@ -576,7 +609,9 @@ static void atomic (lua_State *L) { /* flip current white */ g->currentwhite = cast_byte(otherwhite(g)); g->sweepstrgc = 0; + // 设置当前清理的位置 g->sweepgc = &g->rootgc; + // 切换到回收字符串阶段 g->gcstate = GCSsweepstring; g->estimate = g->totalbytes - udsize; /* first estimate */ } @@ -592,23 +627,24 @@ static l_mem singlestep (lua_State *L) { return 0; } case GCSpropagate: { // 扫描并标记 - if (g->gray) + if (g->gray) // gray list不为空 return propagatemark(g); else { /* no more `gray' objects */ atomic(L); /* finish mark phase */ return 0; } } - case GCSsweepstring: { + case GCSsweepstring: { // 回收字符串 lu_mem old = g->totalbytes; + // 回收g->sweepstrgc位置的散列桶 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); - if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ - g->gcstate = GCSsweep; /* end sweep-string phase */ + if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */// 当所有散列桶都回收完毕,切换到sweep + g->gcstate = GCSsweep; /* end sweep-string phase */ lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPCOST; } - case GCSsweep: { + case GCSsweep: { // 回收字符串以外的其他类型 lu_mem old = g->totalbytes; g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); if (*g->sweepgc == NULL) { /* nothing more to sweep? */ @@ -619,7 +655,7 @@ static l_mem singlestep (lua_State *L) { g->estimate -= old - g->totalbytes; return GCSWEEPMAX*GCSWEEPCOST; } - case GCSfinalize: { + case GCSfinalize: { // 结束阶段,专门处理 tmudata ,调用userdata的__gc方法,释放native引用 if (g->tmudata) { GCTM(L); if (g->estimate > GCFINALIZECOST) @@ -627,6 +663,7 @@ static l_mem singlestep (lua_State *L) { return GCFINALIZECOST; } else { + // 切到pause,进入下一次GC g->gcstate = GCSpause; /* end collection */ g->gcdept = 0; return 0; @@ -637,6 +674,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; @@ -688,29 +726,33 @@ void luaC_fullgc (lua_State *L) { } +//c 向前避障 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); lua_assert(ttype(&o->gch) != LUA_TTABLE); /* must keep invariant? */ - if (g->gcstate == GCSpropagate) - reallymarkobject(g, v); /* restore invariant */ - else /* don't mind */ + if (g->gcstate == GCSpropagate)// 如果在扫描阶段,把新建的v加入gray链 + reallymarkobject(g, v); /* restore invariant */ + else /* don't mind */ // 否则标记为白色,等待下一次GC makewhite(g, o); /* mark as white just to avoid other barriers */ } +//c 向后避障只作用于 table,将table加入 grayagain 链表 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里 t->gclist = g->grayagain; g->grayagain = o; } + //c! 将一个新建的GCGamobject(udata除外,加载其他地方,具体看luaS_newudata)加入root,并标记为白色 //c upvalue 不一定会设为white,所以不会调这个函数 //c 虽然被加入了rootgc,但是不会被轻易回收,lua有双白色缓冲概念 |
