Lua gc 是分步进行的,什么时候开始做呢??
通过GCthreshold控制GC开始时机,GCthreshold就是触发GC的边界值。当一轮GC完整的完成后,GCthreshold 被设置成当前estimate的 gcpause / 100倍。estimate是剔除了userdata后的内存。
带_gc元方法的userdata在第一次被处理时只调用_gc元方法,第二次才是真正回收。在分配新内存时,通过luaC_checkGC检测 总内存是否超过GCthreshold,超过就触发一步GC。
那每步处理多少?
处理多少受gcstepmul影响
void luaC_step (lua_State *L) {
global_State *g = G(L);
//计算这一步要处理多少单位 0 的话就全部处理
l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul;
if (lim == 0)
lim = (MAX_LUMEM-1)/2; /* no limit */
// 计算负债多少 预计是g->GCthreshold; 开始处理 但是现在已经 g->totalbytes 了
g->gcdept += g->totalbytes - g->GCthreshold;
do {
//计算本次还剩多少要处理的
lim -= singlestep(L);
if (g->gcstate == GCSpause)
break;
} while (lim > 0);
if (g->gcstate != GCSpause) {
//处理完这次的量了
if (g->gcdept < GCSTEPSIZE)
// 欠债不太多了 那就扩大边界值
g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/g->gcstepmul;*/
else {
// 欠债太多了 怎么办 那就不停下继续GC吧
g->gcdept -= GCSTEPSIZE;
g->GCthreshold = g->totalbytes;
}
}
else {
lua_assert(g->totalbytes >= g->estimate);
//做了一次完整GC 重新设置边界值 为当前内存(扣除userdata) * gcpause /100
setthreshold(g);
}
}
单步GC处理后将界限值调高了GCSTEPSIZE,也就是涨GCSTEPSIZE内存才发生GC。而每步GC处理的限制 (GCSTEPSIZE/100) * g->gcstepmul。
由此可见 处理 / 涨内存 = ((GCSTEPSIZE/100) * g->gcstepmul ) / GCSTEPSIZE = g->gcstepmul / 100 所以说gcstepmul就是相对于回收速率/分配速率的一个比值。
当gcstepmul <= 100 时 ,每步处理速率 <= 分配速率 ,可能导致无法完成一个完整的GC。gcstepmul越大,代表每步处理的对象越多,同时也会增加处理时间。