summaryrefslogtreecommitdiff
path: root/src/lua51/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua51/lgc.c')
-rw-r--r--src/lua51/lgc.c286
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);
}
}