From 77ac95b9985f5669d6659bfb54728786d28c2ef0 Mon Sep 17 00:00:00 2001 From: chai Date: Mon, 20 Jul 2020 09:42:30 +0800 Subject: *misc --- src/lua51/lgc.c | 68 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 16 deletions(-) (limited to 'src/lua51/lgc.c') diff --git a/src/lua51/lgc.c b/src/lua51/lgc.c index e909c79..f4dbdfb 100644 --- a/src/lua51/lgc.c +++ b/src/lua51/lgc.c @@ -48,7 +48,7 @@ #define VALUEWEAK bitmask(VALUEWEAKBIT) - +// 标记对象,有点类似一个安全声明,mark了的对象不会被回收,会被标记为灰色(大多数情况下)或黑色 #define markvalue(g,o) { checkconsistency(o); \ if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } @@ -66,16 +66,24 @@ static void removeentry (Node *n) { } +//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本身也不会引用其他对象,所以不需要扫描,直接标记为黑色 Table *mt = gco2u(o)->metatable; + // 直接标记为黑色 gray2black(o); /* udata are never gray */ + // 标记一下它的mt和env表 if (mt) markobject(g, mt); markobject(g, gco2u(o)->env); return; @@ -83,6 +91,8 @@ static void reallymarkobject (global_State *g, GCObject *o) { case LUA_TUPVAL: { UpVal *uv = gco2uv(o); markvalue(g, uv->v); + // 当这个upvalue是closed状态,表示这个uv已经没有与其他数据的引用关系 + // 直接标记黑色 if (uv->v == &uv->u.value) /* closed? */ gray2black(o); /* open upvalues are never black */ return; @@ -154,7 +164,8 @@ size_t luaC_separateudata (lua_State *L, int all) { return deadmem; } - +// 遍历table +// 如果是弱表,返回1 static int traversetable (global_State *g, Table *h) { int i; int weakkey = 0; @@ -170,16 +181,23 @@ static int traversetable (global_State *g, Table *h) { h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ h->marked |= cast_byte((weakkey << KEYWEAKBIT) | (weakvalue << VALUEWEAKBIT)); + // 加到weak链表 h->gclist = g->weak; /* must be cleared after GC, ... */ g->weak = obj2gco(h); /* ... so put in the appropriate list */ } } - if (weakkey && weakvalue) return 1; + if (weakkey && weakvalue) return 1; // 如果是弱表,返回1 + + // 如果不是弱表,遍历table的散列部分和数组部分所有元素 + + //数组 if (!weakvalue) { i = h->sizearray; while (i--) markvalue(g, &h->array[i]); } + + //散列 i = sizenode(h); while (i--) { Node *n = gnode(h, i); @@ -277,24 +295,25 @@ static void traversestack (global_State *g, lua_State *l) { static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; lua_assert(isgray(o)); - gray2black(o); + gray2black(o);//预先标记为黑色 switch (o->gch.tt) { - case LUA_TTABLE: { + case LUA_TTABLE: { //扫描table,尝试标记数组和哈希部分 Table *h = gco2h(o); g->gray = h->gclist; + // 如果是弱表,回退回灰色状态 if (traversetable(g, h)) /* table is weak? */ black2gray(o); /* keep it gray */ return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h); } - case LUA_TFUNCTION: { + case LUA_TFUNCTION: { //扫描函数,尝试标记env、upvalue Closure *cl = gco2cl(o); g->gray = cl->c.gclist; traverseclosure(g, cl); return (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues); } - case LUA_TTHREAD: { + case LUA_TTHREAD: { //扫描线程对象, lua_State *th = gco2th(o); g->gray = th->gclist; th->gclist = g->grayagain; @@ -428,11 +447,15 @@ 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 给桶瘦身 if (g->strt.nuse < cast(lu_int32, g->strt.size/4) && - g->strt.size > MINSTRTABSIZE*2) + g->strt.size > MINSTRTABSIZE*2) luaS_resize(L, g->strt.size/2); /* table is too big */ /* check size of buffer */ if (luaZ_sizebuffer(&g->buff) > LUA_MINBUFFER*2) { /* buffer too big? */ @@ -497,15 +520,21 @@ static void markmt (global_State *g) { } +//c 初始化root +//c 将mainthread, /* mark root set */ static void markroot (lua_State *L) { global_State *g = G(L); + // 清空 g->gray = NULL; g->grayagain = NULL; g->weak = NULL; + // 标记mainthread markobject(g, g->mainthread); /* make global table be traversed before main stack */ + // 标记 _G 为灰色 markvalue(g, gt(g->mainthread)); + // 标记注册表为灰色 markvalue(g, registry(L)); markmt(g); g->gcstate = GCSpropagate; @@ -553,15 +582,16 @@ static void atomic (lua_State *L) { } +//c! 单步GC的入口 static l_mem singlestep (lua_State *L) { global_State *g = G(L); /*lua_checkmemory(L);*/ switch (g->gcstate) { - case GCSpause: { + case GCSpause: { // 初始化 markroot(L); /* start a new collection */ return 0; } - case GCSpropagate: { + case GCSpropagate: { // 扫描并标记 if (g->gray) return propagatemark(g); else { /* no more `gray' objects */ @@ -681,27 +711,33 @@ void luaC_barrierback (lua_State *L, Table *t) { 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发生在标记阶段后 void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { global_State *g = G(L); o->gch.next = g->rootgc; g->rootgc = o; - o->gch.marked = luaC_white(g); - o->gch.tt = tt; + o->gch.marked = luaC_white(g);//标记为current white + o->gch.tt = tt;//设置数据类型 } - +//c! 将一个upvalue加入root,由于upvalue是对已经存在的对象的间接引用,所以和普通对象不太一样 void luaC_linkupval (lua_State *L, UpVal *uv) { global_State *g = G(L); GCObject *o = obj2gco(uv); o->gch.next = g->rootgc; /* link upvalue into `rootgc' list */ g->rootgc = o; + // 这里和普通对象不一样 if (isgray(o)) { - if (g->gcstate == GCSpropagate) { + if (g->gcstate == GCSpropagate) {//如果在扫描阶段,直接将对象置为黑色 gray2black(o); /* closed upvalues need barrier */ luaC_barrier(L, uv, uv->v); } - else { /* sweep phase: sweep it (turning it into white) */ + else { /* 否则的话和普通对象一样置为白色 */ /* sweep phase: sweep it (turning it into white) */ makewhite(g, o); lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); } -- cgit v1.1-26-g67d0