这是从lua-5.1.1中分离出来的gc实现代码。
Last active
May 28, 2021 02:40
-
-
Save losophy/544464c2d90da85fc9d0546d3f3dcf53 to your computer and use it in GitHub Desktop.
lua-5.1.1中的gc的实现
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void luaC_link (lua_State *L, GCObject *o, lu_byte tt) { | |
global_State *g = G(L); | |
o->gch.next = g->rootgc; | |
g->rootgc = o;//将对象挂载到 rootgc链表上 | |
o->gch.marked = luaC_white(g);//设置颜色为白色 | |
o->gch.tt = tt;//设置数据的类型 | |
} | |
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) { | |
gray2black(o); /* closed upvalues need barrier */ | |
luaC_barrier(L, uv, uv->v); | |
} | |
else { /* sweep phase: sweep it (turning it into white) */ | |
makewhite(g, o); | |
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | |
} | |
} | |
} | |
Udata *luaS_newudata (lua_State *L, size_t s, Table *e) { | |
Udata *u; | |
if (s > MAX_SIZET - sizeof(Udata)) | |
luaM_toobig(L); | |
u = cast(Udata *, luaM_malloc(L, s + sizeof(Udata))); | |
u->uv.marked = luaC_white(G(L)); /* is not finalized */ | |
u->uv.tt = LUA_TUSERDATA; | |
u->uv.len = s; | |
u->uv.metatable = NULL; | |
u->uv.env = e; | |
/* chain it on udata list (after main thread) */ | |
u->uv.next = G(L)->mainthread->next;//任何时候创建的 udata ,在GC链表中都会放在mainthread之后 。 除此之外,这类型的数据与其他数据并无差别 。 之所以这么做,是因为udata是用户注册的C数据。 在回收时,我们可能会调用用户注册的函数,此时就需要把这些udata统一放在一个地方来处理,这样做是为了方便编写代码 | |
G(L)->mainthread->next = obj2gco(u); | |
return u; | |
} | |
static l_mem singlestep (lua_State *L) { | |
global_State *g = G(L); | |
/*lua_checkmemory(L);*/ | |
switch (g->gcstate) { | |
case GCSpause: { | |
markroot(L); /* start a new collection */ | |
return 0; | |
} | |
case GCSpropagate: { | |
if (g->gray) | |
return propagatemark(g); | |
else { /* no more `gray' objects */ | |
atomic(L); /* finish mark phase */ | |
return 0; | |
} | |
} | |
case GCSsweepstring: { | |
lu_mem old = g->totalbytes; | |
sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); | |
if (g->sweepstrgc >= g->strt.size) /* nothing more to sweep? */ | |
g->gcstate = GCSsweep; /* end sweep-string phase */ | |
lua_assert(old >= g->totalbytes); | |
g->estimate -= old - g->totalbytes; | |
return GCSWEEPCOST; | |
} | |
case GCSsweep: { | |
lu_mem old = g->totalbytes; | |
g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); | |
if (*g->sweepgc == NULL) { /* nothing more to sweep? */ | |
checkSizes(L); | |
g->gcstate = GCSfinalize; /* end sweep phase */ | |
} | |
lua_assert(old >= g->totalbytes); | |
g->estimate -= old - g->totalbytes; | |
return GCSWEEPMAX*GCSWEEPCOST; | |
} | |
case GCSfinalize: { | |
if (g->tmudata) { | |
GCTM(L); | |
if (g->estimate > GCFINALIZECOST) | |
g->estimate -= GCFINALIZECOST; | |
return GCFINALIZECOST; | |
} | |
else { | |
g->gcstate = GCSpause; /* end collection */ | |
g->gcdept = 0; | |
return 0; | |
} | |
} | |
default: lua_assert(0); return 0; | |
} | |
} | |
/* mark root set */ | |
static void markroot (lua_State *L) { | |
global_State *g = G(L); | |
g->gray = NULL; | |
g->grayagain = NULL; | |
g->weak = NULL; | |
markobject(g, g->mainthread); //针对object,标记对象的颜色为灰色,最终调用reallymarkobject函数 | |
/* make global table be traversed before main stack */ | |
markvalue(g, gt(g->mainthread)); //针对TValue,标记对象的颜色为灰色,最终调用reallymarkobject函数 | |
markvalue(g, registry(L)); | |
markmt(g); | |
g->gcstate = GCSpropagate; | |
} | |
static void reallymarkobject (global_State *g, GCObject *o) { | |
lua_assert(iswhite(o) && !isdead(g, o)); | |
white2gray(o); | |
switch (o->gch.tt) { | |
case LUA_TSTRING: {// 对于字符串类型的数据,由于这种类型没有引用其他数据,所以略过将其颜色改为灰色的流程,直接将不是黑色的字符串对象回收即可 | |
return; | |
} | |
case LUA_TUSERDATA: {//对于 udata类型的数据,因为这种类型永远也不会引用其他数据,所以这里也是一步到位,直接将其标记为黑色。 另外,对于这种类型,还需要标记对应的metatable和env表 | |
Table *mt = gco2u(o)->metatable; | |
gray2black(o); /* udata are never gray */ | |
if (mt) markobject(g, mt); | |
markobject(g, gco2u(o)->env); | |
return; | |
} | |
case LUA_TUPVAL: {//对于UpValue类型的数据,如果当前是close状态的话,那么该UpValue 已经没有与其他数据的引用关系了,可以直接标记为黑色 。 至于open状态的 UpValue ,由于其引用状态可能会频繁发生变动,所以留待后面的remarkupvals函数进行原子性的标记 | |
UpVal *uv = gco2uv(o); | |
markvalue(g, uv->v); | |
if (uv->v == &uv->u.value) /* closed? */ | |
gray2black(o); /* open upvalues are never black */ | |
return; | |
} | |
case LUA_TFUNCTION: { | |
gco2cl(o)->c.gclist = g->gray; | |
g->gray = o; | |
break; | |
} | |
case LUA_TTABLE: { | |
gco2h(o)->gclist = g->gray; | |
g->gray = o; | |
break; | |
} | |
case LUA_TTHREAD: { | |
gco2th(o)->gclist = g->gray; | |
g->gray = o; | |
break; | |
} | |
case LUA_TPROTO: { | |
gco2p(o)->gclist = g->gray; | |
g->gray = o; | |
break; | |
} | |
default: lua_assert(0); | |
} | |
} | |
/* | |
** traverse one gray object, turning it to black. | |
** Returns `quantity' traversed. | |
*/ | |
static l_mem propagatemark (global_State *g) { | |
GCObject *o = g->gray; | |
lua_assert(isgray(o)); | |
gray2black(o); | |
switch (o->gch.tt) { | |
case LUA_TTABLE: { | |
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: { | |
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: { | |
lua_State *th = gco2th(o); | |
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: { | |
Proto *p = gco2p(o); | |
g->gray = p->gclist; | |
traverseproto(g, p); | |
return sizeof(Proto) + sizeof(Instruction) * p->sizecode + | |
sizeof(Proto *) * p->sizep + | |
sizeof(TValue) * p->sizek + | |
sizeof(int) * p->sizelineinfo + | |
sizeof(LocVar) * p->sizelocvars + | |
sizeof(TString *) * p->sizeupvalues; | |
} | |
default: lua_assert(0); return 0; | |
} | |
} | |
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);//调用remarkupvals函数去标记open状态的UpValue | |
/* traverse objects cautch by write barrier and by 'remarkupvals' */ | |
propagateall(g);//gray链表又会有新的对象,于是需要调用propagateall再次将gray链表中的对象标记一下 | |
/* remark weak tables */ | |
g->gray = g->weak;//修改gray链表指针,使其指向管理弱表的weak指针 | |
g->weak = NULL; | |
lua_assert(!iswhite(obj2gco(g->mainthread))); | |
markobject(g, L); /* mark running thread *///标记当前的Lua_State指针以及基本的meta表 | |
markmt(g); /* mark basic metatables (again) */ | |
propagateall(g); | |
/* remark gray again */ | |
g->gray = g->grayagain;//修改gray链表指针指向grayagain指针 | |
g->grayagain = NULL; | |
propagateall(g);//调用propagateall函数进行遍历扫描操作 | |
udsize = luaC_separateudata(L, 0); /* separate userdata to be finalized */ | |
marktmu(g); /* mark `preserved' userdata */ | |
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));//将当前白色类型切换到了下一次GC操作的白色类型 | |
g->sweepstrgc = 0; | |
g->sweepgc = &g->rootgc; | |
g->gcstate = GCSsweepstring;//修改状态到下个回收阶段 | |
g->estimate = g->totalbytes - udsize; /* first estimate */ | |
} | |
static int traversetable (global_State *g, Table *h) { | |
int i; | |
int weakkey = 0; | |
int weakvalue = 0; | |
const TValue *mode; | |
if (h->metatable) | |
markobject(g, h->metatable); | |
mode = gfasttm(g, h->metatable, TM_MODE); | |
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? */ | |
h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */ | |
h->marked |= cast_byte((weakkey << KEYWEAKBIT) | | |
(weakvalue << VALUEWEAKBIT)); | |
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 (!weakvalue) { | |
i = h->sizearray; | |
while (i--) | |
markvalue(g, &h->array[i]); | |
} | |
i = sizenode(h); | |
while (i--) { | |
Node *n = gnode(h, i); | |
lua_assert(ttype(gkey(n)) != LUA_TDEADKEY || ttisnil(gval(n))); | |
if (ttisnil(gval(n))) | |
removeentry(n); /* remove empty entries */ | |
else { | |
lua_assert(!ttisnil(gkey(n))); | |
if (!weakkey) markvalue(g, gkey(n)); | |
if (!weakvalue) markvalue(g, gval(n)); | |
} | |
} | |
return weakkey || weakvalue; | |
} | |
static void traverseclosure (global_State *g, Closure *cl) { | |
markobject(g, cl->c.env); | |
if (cl->c.isC) { | |
int i; | |
for (i=0; i<cl->c.nupvalues; i++) /* mark its upvalues */ | |
markvalue(g, &cl->c.upvalue[i]); | |
} | |
else { | |
int i; | |
lua_assert(cl->l.nupvalues == cl->l.p->nups); | |
markobject(g, cl->l.p); | |
for (i=0; i<cl->l.nupvalues; i++) /* mark its upvalues */ | |
markobject(g, cl->l.upvals[i]); | |
} | |
} | |
static void traversestack (global_State *g, lua_State *l) { | |
StkId o, lim; | |
CallInfo *ci; | |
markvalue(g, gt(l)); | |
lim = l->top; | |
for (ci = l->base_ci; ci <= l->ci; ci++) { | |
lua_assert(ci->top <= l->stack_last); | |
if (lim < ci->top) lim = ci->top; | |
} | |
for (o = l->stack; o < l->top; o++) | |
markvalue(g, o); | |
for (; o <= lim; o++) | |
setnilvalue(o); | |
checkstacksizes(l, lim); | |
} | |
/* | |
** 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); | |
for (i=0; i<f->sizek; i++) /* mark literals */ | |
markvalue(g, &f->k[i]); | |
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); | |
} | |
} | |
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) */ | |
t->gclist = g->grayagain; | |
g->grayagain = o; | |
} | |
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 */ | |
makewhite(g, o); /* mark as white just to avoid other barriers */ | |
} | |
/* 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; | |
GCObject **p = &g->mainthread->next; | |
GCObject *curr; | |
while ((curr = *p) != NULL) {//如果该对象不需要回收,就继续处理下一个对象 | |
if (!(iswhite(curr) || all) || isfinalized(gco2u(curr)))//先看该对象有没有注册GC函数 | |
p = &curr->gch.next; /* don't bother with them */ | |
else if (fasttm(L, gco2u(curr)->metatable, TM_GC) == NULL) { | |
markfinalized(gco2u(curr)); /* don't need finalization *///如果没有,就直接标记该对象的状态是finalized | |
p = &curr->gch.next; | |
} | |
else { /* must call its gc method */ | |
deadmem += sizeudata(gco2u(curr)); | |
markfinalized(gco2u(curr));//标记该对象为 finalized | |
*p = curr->gch.next; | |
/* link `curr' at the end of `tmudata' list */ | |
if (g->tmudata == NULL) /* list is empty? *///将这些对象加入tmudata链表中,这里将udata放在一个链表中也是为了统一处理,后面将会提至Ufinalized状态的处理 | |
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; | |
} | |
} | |
} | |
return deadmem; | |
} | |
static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |
GCObject *curr; | |
global_State *g = G(L); | |
int deadmask = otherwhite(g); | |
while ((curr = *p) != NULL && count-- > 0) { | |
if (curr->gch.tt == LUA_TTHREAD) /* sweep open upvalues of each thread */ | |
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; | |
} | |
else { /* must erase `curr' */ | |
lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT)); | |
*p = curr->gch.next; | |
if (curr == g->rootgc) /* is the first element of the list? */ | |
g->rootgc = curr->gch.next; /* adjust first */ | |
freeobj(L, curr); | |
} | |
} | |
return p; | |
} | |
static void GCTM (lua_State *L) { | |
global_State *g = G(L); | |
GCObject *o = g->tmudata->gch.next; /* get first element */ | |
Udata *udata = rawgco2u(o); | |
const TValue *tm; | |
/* remove udata from `tmudata' */ | |
if (o == g->tmudata) /* last element? */ | |
g->tmudata = NULL; | |
else | |
g->tmudata->gch.next = udata->uv.next; | |
udata->uv.next = g->mainthread->next; /* return it to `root' list */ | |
g->mainthread->next = o; | |
makewhite(g, o); | |
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 */ | |
setobj2s(L, L->top, tm); | |
setuvalue(L, L->top+1, udata); | |
L->top += 2; | |
luaD_call(L, L->top - 2, 0); | |
L->allowhook = oldah; /* restore hooks */ | |
g->GCthreshold = oldt; /* restore threshold */ | |
} | |
} | |
void luaC_step (lua_State *L) { | |
global_State *g = G(L); | |
l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;//GCSTEPSIZE 是一个宏,表示每次 GC 的步长大小 。 使用这个宏以及gcstepmul参数,可以计算出这一次回收计划至少回收的内存数量 | |
if (lim == 0) | |
lim = (MAX_LUMEM-1)/2; /* no limit */ | |
g->gcdept += g->totalbytes - g->GCthreshold;//gcdept用于在每次回收之前累加当前使用内存到阔值之间的差值,用于后面计算下一次触发GC的阑值 | |
do {//当计划待回收内存还没有回收完之前,一直循环调用 singlestep 函数来进行回收,除非这里完成了完整的GC | |
lim -= singlestep(L); | |
if (g->gcstate == GCSpause) | |
break; | |
} while (lim > 0);//完成回收之后,设置下一次触发回收操作的阈值;如果完成了一个 GC,那么调用 setthreshold来计算下一次GC的阔值。 | |
if (g->gcstate != GCSpause) {//如果此时状态不是GCSpause ,那么表示没有完成一个GC | |
if (g->gcdept < GCSTEPSIZE)//如果前面保存的 gcdept太小,小于GCSTEPSIZE ,那么下一次阔值就设置得比当前使用内存大GCSTEPSIZE ,即只要再多分配 GCSTEPSIZE 的内存就会再次触发GC | |
g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/ | |
else {//否则将 gcdept 减去 GCSTEPSIZE ,将GCthreshold设置得跟 totalbytes一样,以求尽快触发下一次GC 。 | |
g->gcdept -= GCSTEPSIZE; | |
g->GCthreshold = g->totalbytes; | |
} | |
} | |
else { | |
lua_assert(g->totalbytes >= g->estimate); | |
setthreshold(g);//可以看到 setthreshold只会在一次GC完成之后被调用,而不会影响没有完成的GC全流程 。 因此, setthreshold影响的是两次完整GC之间的时长 。 而gcdept参数会在每次GC完毕之后重新清零,它用于保存一次完整GC的内部状态 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define iscollectable(o) (ttype(o) >= LUA TSTRING) | |
#define CommoHeader GCObject *next; lu_byte tt; lu_byte marked //next:GCObject链表指针,这个指针将所有GC对象都链接在一起形成链表,tt:表示数据的类型,即[lua数据类型](https://github.com/losophy/losophy.github.io/issues/109)的宏,marked : 标记字段,用于存储前面提到的几种颜色 | |
/* | |
** Layout for bit use in `marked' field: | |
** bit 0 - object is white (type 0) | |
** bit 1 - object is white (type 1) | |
** bit 2 - object is black | |
** bit 3 - for userdata: has been finalized | |
** bit 3 - for tables: has weak keys | |
** bit 4 - for tables: has weak values | |
** bit 5 - object is fixed (should not be collected) | |
** bit 6 - object is "super" fixed (only the main thread) | |
*/ | |
#define WHITE0BIT 0 //0型白色 | |
#define WHITE1BIT 1 //l型白色 | |
#define BLACKBIT 2 | |
#define FINALIZEDBIT 3 //FINALIZEDBIT用于标记没有被引用需要回收的 udata 。 udata 的处理与其他数据类型不同,由于它是用户传入的数据,它的回收可能会调用用户注册的GC函数,所以统一来处理。 | |
#define KEYWEAKBIT 3 //用于标记弱表中的键的weak属性 | |
#define VALUEWEAKBIT 4 //T用于标记弱表中的值的weak属性 | |
#define FIXEDBIT 5 //用于表示该对象不可回收,仅用于lua_State对象自身的标记 | |
#define SFIXEDBIT 6 //用于表示该对象不可回收,标记了一系列Lua语法中的关键字对应的字符串为不可回收字符串,具体可以看看luaXinit函数的实现 | |
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) | |
/* | |
** `global state', shared by all threads of this state | |
*/ | |
typedef struct global_State { | |
lu_byte currentwhite;//存放当前GC的白色 | |
lu_byte gcstate; //存放GC状态,分别有以下几种 : GCS pause (暂停阶段) 、 GCSpropagate(传播阶段,用于遍历灰色节点检查对象的引用情况)、 GCSsweepstring (字符串回收阶段) , GCSsweep (回收阶段,用于对除了字符串之外的所有其他数据类型进行回收)和GCSfinalize (终止阶段) 。 | |
int sweepstrgc; //字符串回收阶段,每次针对字符串散列桶的一组字符串进行回收,这个值用于记录对应的散列桶索引 。 | |
GCObject *rootgc; //存放待GC对象的链表,所有对象创建之后都会放入该链表中 | |
GCObject **sweepgc; //待处理的回收数据都存放在rootgc链表中,由于回收阶段不是一次性全部回收这个链表的所有数据,所以使用这个变量来保存当前回收的位置,下一次从这个位置开始继续回收操作 | |
GCObject *gray; //存放灰色节点的链表 | |
GCObject *grayagain; //存放需要一次性扫描处理的灰色节点链表,也就是说,这个链表上所有数据的处理需要一步到位,不能被打断 | |
GCObject *weak; //存放弱表的链表 | |
GCObject *tmudata; //所有带有GC元方法的 udata存放在一个链表中,这个成员指向这千链表的最后一个元素 | |
lu_mem GCthreshold;//开始进行GC的阔值,当totalbytes大于这个值时开始自动GC | |
lu_mem totalbytes; //当前分配的内存大小 | |
lu_mem estimate; //一个估计值,用于保存实际在用的内存大小 | |
lu_mem gcdept; //用于在单次GC之前保存待回收的数据大小 | |
int gcpause; //用于控制下一轮GC开始的时机 | |
int gcstepmul; //控制GC的回收速度 | |
lua_CFunction panic; /* to be called in unprotected errors */ | |
TValue l_registry; | |
struct lua_State *mainthread; | |
UpVal uvhead; /* head of double-linked list of all open upvalues */ | |
struct Table *mt[NUM_TAGS]; /* metatables for basic types */ | |
TString *tmname[TM_N]; /* array with tag-method names */ | |
} global_State; | |
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT) | |
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \ | |
luaC_barrierf(L,obj2gco(p),gcvalue(v)); } | |
#define luaC_barriert(L,t,v) { if (valiswhite(v) && isblack(obj2gco(t))) \ | |
luaC_barrierback(L,t); } | |
#define luaC_objbarrier(L,p,o) \ | |
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \ | |
luaC_barrierf(L,obj2gco(p),obj2gco(o)); } | |
#define luaC_objbarriert(L,t,o) \ | |
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(t))) luaC_barrierback(L,t); } | |
#define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) | |
#define luaC_checkGC(L) { \ | |
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK - 1)); \ | |
if (G(L)->totalbytes >= G(L)->GCthreshold) \ | |
luaC_step(L); } | |
#define setthreshold(g) (g->GCthreshold = (g->estimate/100) * g->gcpause) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment