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.c68
1 files changed, 52 insertions, 16 deletions
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);
}