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.c82
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有双白色缓冲概念