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越大,代表每步處理的對象越多,同時也會增加處理時間。