mirror of
https://github.com/lua/lua
synced 2024-11-22 12:51:30 +03:00
better control for GC cycles
This commit is contained in:
parent
857253cdfc
commit
0b06241483
10
lapi.c
10
lapi.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lapi.c,v 2.16 2004/08/12 17:02:51 roberto Exp roberto $
|
||||
** $Id: lapi.c,v 2.17 2004/08/17 17:45:45 roberto Exp roberto $
|
||||
** Lua API
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -831,7 +831,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
|
||||
break;
|
||||
}
|
||||
case LUA_GCRESTART: {
|
||||
g->GCthreshold = g->nblocks;
|
||||
g->GCthreshold = g->totalbytes;
|
||||
break;
|
||||
}
|
||||
case LUA_GCCOLLECT: {
|
||||
@ -840,13 +840,13 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
|
||||
}
|
||||
case LUA_GCCOUNT: {
|
||||
/* GC values are expressed in Kbytes: #bytes/2^10 */
|
||||
res = cast(int, g->nblocks >> 10);
|
||||
res = cast(int, g->totalbytes >> 10);
|
||||
break;
|
||||
}
|
||||
case LUA_GCSTEP: {
|
||||
lu_mem a = (cast(lu_mem, data) << 10);
|
||||
if (a <= g->nblocks)
|
||||
g->GCthreshold = g->nblocks - a;
|
||||
if (a <= g->totalbytes)
|
||||
g->GCthreshold = g->totalbytes - a;
|
||||
else
|
||||
g->GCthreshold = 0;
|
||||
luaC_step(L);
|
||||
|
84
lgc.c
84
lgc.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lgc.c,v 2.8 2004/08/10 19:17:23 roberto Exp roberto $
|
||||
** $Id: lgc.c,v 2.9 2004/08/24 20:12:06 roberto Exp roberto $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -23,13 +23,11 @@
|
||||
#include "ltm.h"
|
||||
|
||||
|
||||
#define GCSTEPSIZE (40*sizeof(TValue))
|
||||
#define GCSTEPSIZE 1000
|
||||
#define STEPMUL 2
|
||||
#define GCSWEEPMAX 40
|
||||
#define GCSWEEPCOST 1
|
||||
#define GCFINALIZECOST (10*sizeof(TValue))
|
||||
#define WAITNEXTCYCLE (40 * GCSTEPSIZE)
|
||||
#define WAITNEXTCYCLEGN (200 * GCSTEPSIZE)
|
||||
#define GCSWEEPMAX 10
|
||||
#define GCSWEEPCOST 30
|
||||
#define GCFINALIZECOST 100
|
||||
|
||||
|
||||
#define FIXEDMASK bitmask(FIXEDBIT)
|
||||
@ -408,10 +406,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) {
|
||||
global_State *g = G(L);
|
||||
int whitebit = otherwhite(g);
|
||||
int deadmask = whitebit | FIXEDMASK;
|
||||
while ((curr = *p) != NULL) {
|
||||
int generational = g->gcgenerational;
|
||||
while ((curr = *p) != NULL && count-- > 0) {
|
||||
if ((curr->gch.marked ^ whitebit) & deadmask) {
|
||||
lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
|
||||
if (!G(L)->gcgenerational || isdead(g, curr))
|
||||
if (!generational || isdead(g, curr))
|
||||
makewhite(g, curr);
|
||||
if (curr->gch.tt == LUA_TTHREAD)
|
||||
sweepwholelist(L, &gco2th(curr)->openupval);
|
||||
@ -424,17 +423,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) {
|
||||
g->rootgc = curr->gch.next; /* adjust first */
|
||||
freeobj(L, curr);
|
||||
}
|
||||
if (count-- == 0) break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static void sweepstrings (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
sweepwholelist(L, &G(L)->strt.hash[g->sweepstrgc++]);
|
||||
}
|
||||
|
||||
|
||||
static void freelist (lua_State *L, GCObject **p) {
|
||||
while (*p) {
|
||||
@ -532,6 +525,7 @@ static void remarkupvals (global_State *g) {
|
||||
|
||||
static void atomic (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
int aux;
|
||||
lua_assert(g->gray == NULL);
|
||||
/* remark occasional upvalues of (maybe) dead threads */
|
||||
remarkupvals(g);
|
||||
@ -554,7 +548,11 @@ static void atomic (lua_State *L) {
|
||||
g->sweepstrgc = 0;
|
||||
g->sweepgc = &g->rootgc;
|
||||
g->gcstate = GCSsweepstring;
|
||||
if (g->gcgenerational++ > 20) g->gcgenerational = 0;
|
||||
aux = g->gcgenerational;
|
||||
g->gcgenerational = (g->estimate <= 4*g->prevestimate/2);
|
||||
if (!aux) /* last collection was full? */
|
||||
g->prevestimate = g->estimate; /* keep estimate of last full collection */
|
||||
g->estimate = g->totalbytes; /* first estimate */
|
||||
}
|
||||
|
||||
|
||||
@ -562,6 +560,14 @@ static l_mem singlestep (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
/*lua_checkmemory(L);*/
|
||||
switch (g->gcstate) {
|
||||
case GCSpause: {
|
||||
/* start a new collection */
|
||||
if (g->gcgenerational)
|
||||
atomic(L);
|
||||
else
|
||||
markroot(L);
|
||||
return 0;
|
||||
}
|
||||
case GCSpropagate: {
|
||||
if (g->gray)
|
||||
return propagatemark(g);
|
||||
@ -571,33 +577,31 @@ static l_mem singlestep (lua_State *L) {
|
||||
}
|
||||
}
|
||||
case GCSsweepstring: {
|
||||
sweepstrings(L);
|
||||
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 */
|
||||
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 */
|
||||
}
|
||||
return GCSWEEPCOST;
|
||||
g->estimate -= old - g->totalbytes;
|
||||
return GCSWEEPMAX*GCSWEEPCOST;
|
||||
}
|
||||
case GCSfinalize: {
|
||||
if (g->tmudata) {
|
||||
GCTM(L);
|
||||
return GCFINALIZECOST;
|
||||
}
|
||||
else { /* no more `udata' to finalize */
|
||||
if (g->gcgenerational) {
|
||||
atomic(L);
|
||||
return WAITNEXTCYCLEGN;
|
||||
}
|
||||
else {
|
||||
markroot(L); /* may restart collection */
|
||||
return WAITNEXTCYCLE;
|
||||
}
|
||||
else {
|
||||
g->gcstate = GCSpause; /* end collection */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
default: lua_assert(0); return 0;
|
||||
@ -607,18 +611,30 @@ static l_mem singlestep (lua_State *L) {
|
||||
|
||||
void luaC_step (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
|
||||
l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
|
||||
/*printf("step(%c): ", g->gcgenerational?'g':' ');*/
|
||||
do {
|
||||
/*printf("%c", "_pswf"[g->gcstate]);*/
|
||||
lim -= singlestep(L);
|
||||
if (g->gcstate == GCSpause)
|
||||
break;
|
||||
} while (lim > 0);
|
||||
g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL;
|
||||
lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL);
|
||||
/*printf("\n");*/
|
||||
if (g->gcstate != GCSpause)
|
||||
g->GCthreshold = g->totalbytes + GCSTEPSIZE; /* - lim/STEPMUL; */
|
||||
else {
|
||||
/*printf("---\n");*/
|
||||
lua_assert(g->totalbytes >= g->estimate);
|
||||
g->GCthreshold = 2*g->estimate;
|
||||
if (g->GCthreshold < g->totalbytes + GCSTEPSIZE)
|
||||
g->GCthreshold = g->totalbytes + GCSTEPSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void luaC_fullgc (lua_State *L) {
|
||||
global_State *g = G(L);
|
||||
if (g->gcstate == GCSpropagate || g->gcgenerational) {
|
||||
if (g->gcstate <= GCSpropagate || g->gcgenerational) {
|
||||
g->gcgenerational = 0;
|
||||
/* reset sweep marks to sweep all elements (returning them to white) */
|
||||
g->sweepstrgc = 0;
|
||||
@ -631,6 +647,7 @@ void luaC_fullgc (lua_State *L) {
|
||||
}
|
||||
/* finish any pending sweep phase */
|
||||
while (g->gcstate != GCSfinalize) {
|
||||
lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
|
||||
singlestep(L);
|
||||
}
|
||||
markroot(L);
|
||||
@ -639,7 +656,8 @@ void luaC_fullgc (lua_State *L) {
|
||||
singlestep(L);
|
||||
g->gcgenerational = 0; /* keep it in this mode */
|
||||
}
|
||||
g->GCthreshold = g->nblocks + GCSTEPSIZE;
|
||||
lua_assert(g->estimate == g->totalbytes);
|
||||
g->GCthreshold = 2*g->estimate;
|
||||
luaC_callGCTM(L); /* call finalizers */
|
||||
}
|
||||
|
||||
@ -686,7 +704,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) {
|
||||
}
|
||||
else { /* sweep phase: sweep it (turning it into white) */
|
||||
makewhite(g, o);
|
||||
lua_assert(g->gcstate != GCSfinalize);
|
||||
lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
13
lgc.h
13
lgc.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lgc.h,v 2.6 2004/08/10 19:17:23 roberto Exp roberto $
|
||||
** $Id: lgc.h,v 2.7 2004/08/24 20:12:06 roberto Exp roberto $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -14,10 +14,11 @@
|
||||
/*
|
||||
** Possible states of the Garbage Collector
|
||||
*/
|
||||
#define GCSpropagate 0
|
||||
#define GCSsweepstring 1
|
||||
#define GCSsweep 2
|
||||
#define GCSfinalize 3
|
||||
#define GCSpause 0
|
||||
#define GCSpropagate 1
|
||||
#define GCSsweepstring 2
|
||||
#define GCSsweep 3
|
||||
#define GCSfinalize 4
|
||||
|
||||
|
||||
/*
|
||||
@ -71,7 +72,7 @@
|
||||
#define luaC_white(g) cast(lu_byte, (g)->currentwhite)
|
||||
|
||||
|
||||
#define luaC_checkGC(L) { if (G(L)->nblocks >= G(L)->GCthreshold) \
|
||||
#define luaC_checkGC(L) { if (G(L)->totalbytes >= G(L)->GCthreshold) \
|
||||
luaC_step(L); }
|
||||
|
||||
|
||||
|
5
lmem.c
5
lmem.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lmem.c,v 1.63 2003/11/27 18:18:37 roberto Exp roberto $
|
||||
** $Id: lmem.c,v 1.64 2004/04/30 20:13:38 roberto Exp roberto $
|
||||
** Interface to Memory Manager
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -77,8 +77,7 @@ void *luaM_realloc (lua_State *L, void *block, lu_mem osize, lu_mem nsize) {
|
||||
if (block == NULL && nsize > 0)
|
||||
luaD_throw(L, LUA_ERRMEM);
|
||||
lua_assert((nsize == 0) == (block == NULL));
|
||||
g->nblocks -= osize;
|
||||
g->nblocks += nsize;
|
||||
g->totalbytes = (g->totalbytes - osize) + nsize;
|
||||
return block;
|
||||
}
|
||||
|
||||
|
14
lstate.c
14
lstate.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.c,v 2.10 2004/06/17 14:25:31 roberto Exp roberto $
|
||||
** $Id: lstate.c,v 2.11 2004/08/24 20:12:06 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -77,11 +77,12 @@ static void freestack (lua_State *L, lua_State *L1) {
|
||||
*/
|
||||
static void f_luaopen (lua_State *L, void *ud) {
|
||||
Udata *u; /* head of udata list */
|
||||
global_State *g = G(L);
|
||||
UNUSED(ud);
|
||||
u = cast(Udata *, luaM_malloc(L, sizeudata(0)));
|
||||
u->uv.len = 0;
|
||||
u->uv.metatable = NULL;
|
||||
G(L)->firstudata = obj2gco(u);
|
||||
g->firstudata = obj2gco(u);
|
||||
luaC_link(L, obj2gco(u), LUA_TUSERDATA);
|
||||
setbit(u->uv.marked, FIXEDBIT);
|
||||
setbit(L->marked, FIXEDBIT);
|
||||
@ -93,7 +94,8 @@ static void f_luaopen (lua_State *L, void *ud) {
|
||||
luaT_init(L);
|
||||
luaX_init(L);
|
||||
luaS_fix(luaS_newliteral(L, MEMERRMSG));
|
||||
G(L)->GCthreshold = 4*G(L)->nblocks;
|
||||
g->GCthreshold = 4*g->totalbytes;
|
||||
g->prevestimate = g->estimate = g->totalbytes;
|
||||
}
|
||||
|
||||
|
||||
@ -128,7 +130,7 @@ static void close_state (lua_State *L) {
|
||||
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
|
||||
luaZ_freebuffer(L, &g->buff);
|
||||
freestack(L, L);
|
||||
lua_assert(g->nblocks == sizeof(LG));
|
||||
lua_assert(g->totalbytes == sizeof(LG));
|
||||
(*g->realloc)(g->ud, fromstate(L), state_size(LG), 0);
|
||||
}
|
||||
|
||||
@ -177,7 +179,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||
setnilvalue(registry(L));
|
||||
luaZ_initbuffer(L, &g->buff);
|
||||
g->panic = NULL;
|
||||
g->gcstate = GCSfinalize;
|
||||
g->gcstate = GCSpause;
|
||||
g->gcgenerational = 0;
|
||||
g->rootgc = obj2gco(L);
|
||||
g->sweepstrgc = 0;
|
||||
@ -190,7 +192,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
||||
setnilvalue(gkey(g->dummynode));
|
||||
setnilvalue(gval(g->dummynode));
|
||||
g->dummynode->next = NULL;
|
||||
g->nblocks = sizeof(LG);
|
||||
g->totalbytes = sizeof(LG);
|
||||
if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
|
||||
/* memory allocation error: free partial state */
|
||||
close_state(L);
|
||||
|
6
lstate.h
6
lstate.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
** $Id: lstate.h,v 2.5 2004/06/02 19:07:55 roberto Exp roberto $
|
||||
** $Id: lstate.h,v 2.6 2004/08/24 20:12:06 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
@ -82,7 +82,9 @@ typedef struct global_State {
|
||||
GCObject *tmudata; /* list of userdata to be GC */
|
||||
Mbuffer buff; /* temporary buffer for string concatentation */
|
||||
lu_mem GCthreshold;
|
||||
lu_mem nblocks; /* number of `bytes' currently allocated */
|
||||
lu_mem totalbytes; /* number of bytes currently allocated */
|
||||
lu_mem estimate; /* an estimate of number of bytes actually in use */
|
||||
lu_mem prevestimate; /* previous estimate */
|
||||
lua_CFunction panic; /* to be called in unprotected errors */
|
||||
TValue _registry;
|
||||
struct lua_State *mainthread;
|
||||
|
Loading…
Reference in New Issue
Block a user