1
0
mirror of https://github.com/lua/lua.git synced 2025-01-14 05:43:00 +08:00

First criteria for shifts minor<->major

This commit is contained in:
Roberto Ierusalimschy 2023-12-07 15:45:11 -03:00
parent 789e7acdea
commit 925fe8a0f2
8 changed files with 186 additions and 127 deletions

25
lapi.c
View File

@ -1204,26 +1204,29 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
break; break;
} }
case LUA_GCGEN: { case LUA_GCGEN: {
unsigned int minormul = va_arg(argp, unsigned int); int minormul = va_arg(argp, int);
unsigned int majormul = va_arg(argp, unsigned int); int minormajor = va_arg(argp, int);
int majorminor = va_arg(argp, int);
res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN;
if (minormul != 0) if (minormul >= 0)
setgcparam(g, genminormul, minormul); setgcparam(g, genminormul, minormul);
if (majormul != 0) if (minormajor >= 0)
setgcparam(g, genmajormul, majormul); setgcparam(g, minormajor, minormajor);
if (majorminor >= 0)
setgcparam(g, majorminor, majorminor);
luaC_changemode(L, KGC_GENMINOR); luaC_changemode(L, KGC_GENMINOR);
break; break;
} }
case LUA_GCINC: { case LUA_GCINC: {
unsigned int pause = va_arg(argp, unsigned int); int pause = va_arg(argp, int);
unsigned int stepmul = va_arg(argp, unsigned int); int stepmul = va_arg(argp, int);
unsigned int stepsize = va_arg(argp, unsigned int); int stepsize = va_arg(argp, int);
res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN; res = (g->gckind == KGC_INC) ? LUA_GCINC : LUA_GCGEN;
if (pause != 0) if (pause >= 0)
setgcparam(g, gcpause, pause); setgcparam(g, gcpause, pause);
if (stepmul != 0) if (stepmul >= 0)
setgcparam(g, gcstepmul, stepmul); setgcparam(g, gcstepmul, stepmul);
if (stepsize != 0) if (stepsize >= 0)
g->gcstepsize = (stepsize <= log2maxs(l_obj)) ? stepsize g->gcstepsize = (stepsize <= log2maxs(l_obj)) ? stepsize
: log2maxs(l_obj); : log2maxs(l_obj);
luaC_changemode(L, KGC_INC); luaC_changemode(L, KGC_INC);

View File

@ -224,14 +224,15 @@ static int luaB_collectgarbage (lua_State *L) {
return 1; return 1;
} }
case LUA_GCGEN: { case LUA_GCGEN: {
int minormul = (int)luaL_optinteger(L, 2, 0); int minormul = (int)luaL_optinteger(L, 2, -1);
int majormul = (int)luaL_optinteger(L, 3, 0); int majorminor = (int)luaL_optinteger(L, 3, -1);
return pushmode(L, lua_gc(L, o, minormul, majormul)); int minormajor = (int)luaL_optinteger(L, 4, -1);
return pushmode(L, lua_gc(L, o, minormul, majorminor, minormajor));
} }
case LUA_GCINC: { case LUA_GCINC: {
int pause = (int)luaL_optinteger(L, 2, 0); int pause = (int)luaL_optinteger(L, 2, -1);
int stepmul = (int)luaL_optinteger(L, 3, 0); int stepmul = (int)luaL_optinteger(L, 3, -1);
int stepsize = (int)luaL_optinteger(L, 4, 0); int stepsize = (int)luaL_optinteger(L, 4, -1);
return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize)); return pushmode(L, lua_gc(L, o, pause, stepmul, stepsize));
} }
default: { default: {

81
lgc.c
View File

@ -1205,20 +1205,21 @@ static void correctgraylists (global_State *g) {
/* /*
** Mark black 'OLD1' objects when starting a new young collection. ** Mark black 'OLD1' objects when starting a new young collection.
** Gray objects are already in some gray list, and so will be visited in ** Gray objects are already in some gray list, and so will be visited in
** the atomic step. The counter 'GCmajorminor' keeps how many objects to ** the atomic step. Returns the number of objects that became old.
** become old before a major collection.
*/ */
static void markold (global_State *g, GCObject *from, GCObject *to) { static l_obj markold (global_State *g, GCObject *from, GCObject *to) {
GCObject *p; GCObject *p;
l_obj count = 0;
for (p = from; p != to; p = p->next) { for (p = from; p != to; p = p->next) {
if (getage(p) == G_OLD1) { if (getage(p) == G_OLD1) {
lua_assert(!iswhite(p)); lua_assert(!iswhite(p));
setage(p, G_OLD); /* now they are old */ setage(p, G_OLD); /* now they are old */
g->GCmajorminor--; /* one more old object */ count++; /* one more old object */
if (isblack(p)) if (isblack(p))
reallymarkobject(g, p); reallymarkobject(g, p);
} }
} }
return count;
} }
@ -1240,7 +1241,7 @@ static void finishgencycle (lua_State *L, global_State *g) {
*/ */
static void atomic2major (lua_State *L, global_State *g) { static void atomic2major (lua_State *L, global_State *g) {
l_obj stepsize = cast(l_obj, 1) << g->gcstepsize; l_obj stepsize = cast(l_obj, 1) << g->gcstepsize;
g->GCmajorminor = gettotalobjs(g); g->GCmajorminor = g->marked; /* number of live objects */
g->gckind = KGC_GENMAJOR; g->gckind = KGC_GENMAJOR;
g->reallyold = g->old1 = g->survival = NULL; g->reallyold = g->old1 = g->survival = NULL;
g->finobjrold = g->finobjold1 = g->finobjsur = NULL; g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
@ -1249,30 +1250,54 @@ static void atomic2major (lua_State *L, global_State *g) {
} }
/*
** Decide whether to shift to major mode. It tests two conditions:
** 1) Whether the number of added old objects in this collection is more
** than half the number of new objects. ("step" is the number of objects
** created between minor collections. Except for forward barriers, it
** is the maximum number of objects that can become old in each minor
** collection.)
** 2) Whether the accumulated number of added old objects is larger
** than 'minormajor'% of the number of lived objects after the last
** major collection. (That percentage is computed in 'limit'.)
*/
static int checkminormajor (lua_State *L, global_State *g, l_obj addedold1) {
l_obj step = applygcparam(g, genminormul, g->GCmajorminor);
l_obj limit = applygcparam(g, minormajor, g->GCmajorminor);
//printf("-> major? %ld %ld %ld %ld (%ld)\n", g->marked, limit, step, addedold1, gettotalobjs(g));
if (addedold1 >= (step >> 1) || g->marked >= limit) {
atomic2major(L, g); /* go to major mode */
return 1;
}
return 0; /* stay in minor mode */
}
/* /*
** Does a young collection. First, mark 'OLD1' objects. Then does the ** Does a young collection. First, mark 'OLD1' objects. Then does the
** atomic step. Then, check whether to continue in minor mode. If so, ** atomic step. Then, check whether to continue in minor mode. If so,
** sweep all lists and advance pointers. Finally, finish the collection. ** sweep all lists and advance pointers. Finally, finish the collection.
*/ */
static void youngcollection (lua_State *L, global_State *g) { static void youngcollection (lua_State *L, global_State *g) {
l_obj addedold1 = 0;
l_obj marked = g->marked; /* preserve 'g->marked' */
GCObject **psurvival; /* to point to first non-dead survival object */ GCObject **psurvival; /* to point to first non-dead survival object */
GCObject *dummy; /* dummy out parameter to 'sweepgen' */ GCObject *dummy; /* dummy out parameter to 'sweepgen' */
lua_assert(g->gcstate == GCSpropagate); lua_assert(g->gcstate == GCSpropagate);
g->marked = 0;
if (g->firstold1) { /* are there regular OLD1 objects? */ if (g->firstold1) { /* are there regular OLD1 objects? */
markold(g, g->firstold1, g->reallyold); /* mark them */ addedold1 += markold(g, g->firstold1, g->reallyold); /* mark them */
g->firstold1 = NULL; /* no more OLD1 objects (for now) */ g->firstold1 = NULL; /* no more OLD1 objects (for now) */
} }
markold(g, g->finobj, g->finobjrold); addedold1 += markold(g, g->finobj, g->finobjrold);
markold(g, g->tobefnz, NULL); addedold1 += markold(g, g->tobefnz, NULL);
atomic(L); atomic(L); /* will lose 'g->marked' */
/* keep total number of added old1 objects */
g->marked = marked + addedold1;
/* decide whether to shift to major mode */ /* decide whether to shift to major mode */
if (g->GCmajorminor <= 0) { /* ?? */ if (checkminormajor(L, g, addedold1))
atomic2major(L, g); /* go to major mode */
return; /* nothing else to be done here */ return; /* nothing else to be done here */
}
/* sweep nursery and get a pointer to its last live element */ /* sweep nursery and get a pointer to its last live element */
g->gcstate = GCSswpallgc; g->gcstate = GCSswpallgc;
@ -1319,7 +1344,8 @@ static void atomic2gen (lua_State *L, global_State *g) {
sweep2old(L, &g->tobefnz); sweep2old(L, &g->tobefnz);
g->gckind = KGC_GENMINOR; g->gckind = KGC_GENMINOR;
g->GCmajorminor = applygcparam(g, genmajormul, g->marked); g->GCmajorminor = g->marked; /* "base" for number of objects */
g->marked = 0; /* to count the number of added old1 objects */
finishgencycle(L, g); finishgencycle(L, g);
} }
@ -1329,7 +1355,7 @@ static void atomic2gen (lua_State *L, global_State *g) {
** total number of objects grows 'genminormul'%. ** total number of objects grows 'genminormul'%.
*/ */
static void setminordebt (global_State *g) { static void setminordebt (global_State *g) {
luaE_setdebt(g, applygcparam(g, genminormul, gettotalobjs(g))); luaE_setdebt(g, applygcparam(g, genminormul, g->GCmajorminor));
} }
@ -1369,13 +1395,11 @@ static void enterinc (global_State *g) {
*/ */
void luaC_changemode (lua_State *L, int newmode) { void luaC_changemode (lua_State *L, int newmode) {
global_State *g = G(L); global_State *g = G(L);
if (g->gckind == KGC_GENMAJOR) /* doing major collections? */
g->gckind = KGC_INC; /* already incremental but in name */
if (newmode != g->gckind) { /* does it need to change? */ if (newmode != g->gckind) { /* does it need to change? */
if (newmode == KGC_INC) { /* entering incremental mode? */ if (newmode == KGC_INC) /* entering incremental mode? */
if (g->gckind == KGC_GENMAJOR) enterinc(g); /* entering incremental mode */
g->gckind = KGC_INC; /* already incremental but in name */
else
enterinc(g); /* entering incremental mode */
}
else { else {
lua_assert(newmode == KGC_GENMINOR); lua_assert(newmode == KGC_GENMINOR);
entergen(L, g); entergen(L, g);
@ -1396,16 +1420,24 @@ static void fullgen (lua_State *L, global_State *g) {
/* /*
** After an atomic incremental step from a major collection, ** After an atomic incremental step from a major collection,
** check whether collector could return to minor collections. ** check whether collector could return to minor collections.
** It checks whether the number of objects 'tobecollected'
** is greater than 'majorminor'% of the number of objects added
** since the last collection ('addedobjs').
*/ */
static int checkmajorminor (lua_State *L, global_State *g) { static int checkmajorminor (lua_State *L, global_State *g) {
if (g->gckind == KGC_GENMAJOR) { if (g->gckind == KGC_GENMAJOR) {
l_obj numobjs = gettotalobjs(g); /* current count */ l_obj numobjs = gettotalobjs(g);
if (g->marked < numobjs - (numobjs >> 2)) { /* ?? */ l_obj addedobjs = numobjs - g->GCmajorminor;
l_obj limit = applygcparam(g, majorminor, addedobjs);
l_obj tobecollected = numobjs - g->marked;
//printf("-> minor? %ld %ld %ld\n", tobecollected, limit, numobjs);
if (tobecollected > limit) {
atomic2gen(L, g); /* return to generational mode */ atomic2gen(L, g); /* return to generational mode */
setminordebt(g); setminordebt(g);
return 0; /* exit incremental collection */ return 0; /* exit incremental collection */
} }
} }
g->GCmajorminor = g->marked; /* prepare for next collection */
return 1; /* stay doing incremental collections */ return 1; /* stay doing incremental collections */
} }
@ -1634,8 +1666,6 @@ void luaC_step (lua_State *L) {
if (!gcrunning(g)) /* not running? */ if (!gcrunning(g)) /* not running? */
luaE_setdebt(g, 2000); luaE_setdebt(g, 2000);
else { else {
//printf("> step: %d %d %ld %ld -> ", g->gckind, g->gcstate, gettotalobjs(g), g->GCdebt);
switch (g->gckind) { switch (g->gckind) {
case KGC_INC: case KGC_GENMAJOR: case KGC_INC: case KGC_GENMAJOR:
incstep(L, g); incstep(L, g);
@ -1645,7 +1675,6 @@ void luaC_step (lua_State *L) {
setminordebt(g); setminordebt(g);
break; break;
} }
//printf("%d %d %ld %ld\n", g->gckind, g->gcstate, gettotalobjs(g), g->GCdebt);
} }
} }

48
lgc.h
View File

@ -161,10 +161,24 @@
/* Default Values for GC parameters */ /* Default Values for GC parameters */
/* generational */ /*
** Minor collections will shift to major ones after LUAI_MINORMAJOR%
** objects become old.
*/
#define LUAI_MINORMAJOR 100
/*
** Major collections will shift to minor ones after a collection
** collects at least LUAI_MAJORMINOR% of the new objects.
*/
#define LUAI_MAJORMINOR 80
/*
** A young (minor) collection will run after creating LUAI_GENMINORMUL%
** new objects.
*/
#define LUAI_GENMINORMUL 20
#define LUAI_GENMAJORMUL 100 /* major multiplier */
#define LUAI_GENMINORMUL 20 /* minor multiplier */
/* incremental */ /* incremental */
@ -187,27 +201,17 @@
/* /*
** Macros to set and apply GC parameters. GC parameters are given in ** Macros to set and apply GC parameters. GC parameters are given in
** percentage points, but are stored as lu_byte. To reduce their ** percentage points, but are stored as lu_byte. To avoid repeated
** values and avoid repeated divisions by 100, these macros store ** divisions by 100, these macros store the original parameter
** the original parameter multiplied by 2^n and divided by 100. ** multiplied by 128 and divided by 100. To apply them, if it first
** To apply them, the value is divided by 2^n (a shift) and then ** divides the value by 128 it may lose precision; if it first
** multiplied by the stored parameter, yielding ** multiplies by the parameter, it may overflow. So, it first divides
** value / 2^n * (original parameter * 2^n / 100), or approximately ** by 32, then multiply by the parameter, and then divides the result by
** (value * original parameter / 100). ** 4.
**
** For most parameters, which are typically larger than 100%, 2^n is
** 16 (2^4), allowing maximum values up to ~1500%, with a granularity
** of ~6%. For the minor multiplier, which is typically smaller,
** 2^n is 64 (2^6) to allow more precision. In that case, the maximum
** value is ~400%, with a granularity of ~1.5%.
*/ */
#define gcparamshift(p) \
(offsetof(global_State, p) == offsetof(global_State, genminormul) ? 6 : 4)
#define setgcparam(g,p,v) \
(g->p = (cast_uint(v) << gcparamshift(p)) / 100u)
#define applygcparam(g,p,v) (((v) >> gcparamshift(p)) * g->p)
#define setgcparam(g,p,v) (g->gcp##p = (cast_uint(v) << 7) / 100u)
#define applygcparam(g,p,v) ((((v) >> 5) * g->gcp##p) >> 2)
/* /*

View File

@ -368,8 +368,9 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud, unsigned int seed) {
setgcparam(g, gcpause, LUAI_GCPAUSE); setgcparam(g, gcpause, LUAI_GCPAUSE);
setgcparam(g, gcstepmul, LUAI_GCMUL); setgcparam(g, gcstepmul, LUAI_GCMUL);
g->gcstepsize = LUAI_GCSTEPSIZE; g->gcstepsize = LUAI_GCSTEPSIZE;
setgcparam(g, genmajormul, LUAI_GENMAJORMUL);
setgcparam(g, genminormul, LUAI_GENMINORMUL); setgcparam(g, genminormul, LUAI_GENMINORMUL);
setgcparam(g, minormajor, LUAI_MINORMAJOR);
setgcparam(g, majorminor, LUAI_MAJORMINOR);
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */ /* memory allocation error: free partial state */

View File

@ -264,16 +264,17 @@ typedef struct global_State {
TValue l_registry; TValue l_registry;
TValue nilvalue; /* a nil value */ TValue nilvalue; /* a nil value */
unsigned int seed; /* randomized seed for hashes */ unsigned int seed; /* randomized seed for hashes */
unsigned short gcpgenminormul; /* control minor generational collections */
unsigned short gcpmajorminor; /* control shift major->minor */
unsigned short gcpminormajor; /* control shift minor->major */
unsigned short gcpgcpause; /* size of pause between successive GCs */
unsigned short gcpgcstepmul; /* GC "speed" */
lu_byte currentwhite; lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */ lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */ lu_byte gckind; /* kind of GC running */
lu_byte gcstopem; /* stops emergency collections */ lu_byte gcstopem; /* stops emergency collections */
lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */
lu_byte gcstp; /* control whether GC is running */ lu_byte gcstp; /* control whether GC is running */
lu_byte gcemergency; /* true if this is an emergency collection */ lu_byte gcemergency; /* true if this is an emergency collection */
lu_byte gcpause; /* size of pause between successive GCs */
lu_byte gcstepmul; /* GC "speed" */
lu_byte gcstepsize; /* (log2 of) GC granularity */ lu_byte gcstepsize; /* (log2 of) GC granularity */
GCObject *allgc; /* list of all collectable objects */ GCObject *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */ GCObject **sweepgc; /* current position of sweep in list */

2
lua.c
View File

@ -646,7 +646,7 @@ static int pmain (lua_State *L) {
luai_openlibs(L); /* open standard libraries */ luai_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */ createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCRESTART); /* start GC... */ lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */ lua_gc(L, LUA_GCGEN, -1, -1, -1); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */ if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */ return 0; /* error running LUA_INIT */

View File

@ -621,7 +621,8 @@ that is inaccessible from Lua.
another live object refer to the object.) another live object refer to the object.)
Because Lua has no knowledge about @N{C code}, Because Lua has no knowledge about @N{C code},
it never collects objects accessible through the registry @see{registry}, it never collects objects accessible through the registry @see{registry},
which includes the global environment @see{globalenv}. which includes the global environment @see{globalenv} and
the main thread.
The garbage collector (GC) in Lua can work in two modes: The garbage collector (GC) in Lua can work in two modes:
@ -638,8 +639,8 @@ therefore, optimal settings are also non-portable.
You can change the GC mode and parameters by calling You can change the GC mode and parameters by calling
@Lid{lua_gc} @N{in C} @Lid{lua_gc} @N{in C}
or @Lid{collectgarbage} in Lua. or @Lid{collectgarbage} in Lua.
You can also use these functions to control You can also use these functions to control the collector directly,
the collector directly (e.g., to stop and restart it). for instance to stop or restart it.
} }
@ -656,39 +657,36 @@ and the @def{garbage-collector step size}.
The garbage-collector pause The garbage-collector pause
controls how long the collector waits before starting a new cycle. controls how long the collector waits before starting a new cycle.
The collector starts a new cycle when the use of memory The collector starts a new cycle when the number of objects
hits @M{n%} of the use after the previous collection. hits @M{n%} of the total after the previous collection.
Larger values make the collector less aggressive. Larger values make the collector less aggressive.
Values equal to or less than 100 mean the collector will not wait to Values equal to or less than 100 mean the collector will not wait to
start a new cycle. start a new cycle.
A value of 200 means that the collector waits for the total memory in use A value of 200 means that the collector waits for
to double before starting a new cycle. the total number of objects to double before starting a new cycle.
The default value is 200; the maximum value is 1000. The default value is 200; the maximum value is 1000.
The garbage-collector step multiplier The garbage-collector step multiplier
controls the speed of the collector relative to controls the speed of the collector relative to
memory allocation, object creation,
that is, that is,
how many elements it marks or sweeps for each how many objects it marks or sweeps for each object created.
kilobyte of memory allocated. Larger values make the collector more aggressive.
Larger values make the collector more aggressive but also increase Beware that values too small can
the size of each incremental step. make the collector too slow to ever finish a cycle.
You should not use values less than 100, The default value is 300; the maximum value is 1000.
because they make the collector too slow and
can result in the collector never finishing a cycle.
The default value is 100; the maximum value is 1000.
The garbage-collector step size controls the The garbage-collector step size controls the
size of each incremental step, size of each incremental step,
specifically how many bytes the interpreter allocates specifically how many objects the interpreter creates
before performing a step. before performing a step.
This parameter is logarithmic: This parameter is logarithmic:
A value of @M{n} means the interpreter will allocate @M{2@sp{n}} A value of @M{n} means the interpreter will create @M{2@sp{n}}
bytes between steps and perform equivalent work during the step. objects between steps and perform equivalent work during the step.
A large value (e.g., 60) makes the collector a stop-the-world A large value (e.g., 60) makes the collector a stop-the-world
(non-incremental) collector. (non-incremental) collector.
The default value is 13, The default value is 8,
which means steps of approximately @N{8 Kbytes}. which means steps of approximately @N{256 objects}.
} }
@ -697,31 +695,44 @@ which means steps of approximately @N{8 Kbytes}.
In generational mode, In generational mode,
the collector does frequent @emph{minor} collections, the collector does frequent @emph{minor} collections,
which traverses only objects recently created. which traverses only objects recently created.
If after a minor collection the use of memory is still above a limit, If after a minor collection the number of objects is above a limit,
the collector does a stop-the-world @emph{major} collection, the collector shifts to a @emph{major} collection,
which traverses all objects. which traverses all objects.
The generational mode uses two parameters: The collector will then stay doing major collections until
the @def{minor multiplier} and the @def{the major multiplier}. it detects that the program is generating enough garbage to justify
going back to minor collections.
The generational mode uses three parameters:
the @def{minor multiplier}, the @def{minor-major multiplier},
and the @def{major-minor multiplier}.
The minor multiplier controls the frequency of minor collections. The minor multiplier controls the frequency of minor collections.
For a minor multiplier @M{x}, For a minor multiplier @M{x},
a new minor collection will be done when memory a new minor collection will be done when the number of objects
grows @M{x%} larger than the memory in use after the previous major grows @M{x%} larger than the number in use just after the last collection.
collection.
For instance, for a multiplier of 20, For instance, for a multiplier of 20,
the collector will do a minor collection when the use of memory the collector will do a minor collection when the number of objects
gets 20% larger than the use after the previous major collection. gets 20% larger than the total after the last major collection.
The default value is 20; the maximum value is 200. The default value is 20.
The major multiplier controls the frequency of major collections. The minor-major multiplier controls the shift to major collections.
For a major multiplier @M{x}, For a multiplier @M{x},
a new major collection will be done when memory the collector will shift to a major collection
grows @M{x%} larger than the memory in use after the previous major when the number of old objects grows @M{x%} larger
collection. than the total after the previous major collection.
For instance, for a multiplier of 100, For instance, for a multiplier of 100,
the collector will do a major collection when the use of memory the collector will do a major collection when the number of old objects
gets larger than twice the use after the previous collection. gets larger than twice the total after the previous major collection.
The default value is 100; the maximum value is 1000. The default value is 100.
The major-minor multiplier controls the shift back to minor collections.
For a multiplier @M{x},
the collector will shift back to minor collections
after a major collection collects at least @M{x%} of the allocated objects.
In particular, for a multiplier of 0,
the collector will immediately shift back to minor collections
after doing one cycle of major collections.
The default value is 20.
} }
@ -3311,9 +3322,8 @@ Returns the remainder of dividing the current amount of bytes of
memory in use by Lua by 1024. memory in use by Lua by 1024.
} }
@item{@id{LUA_GCSTEP} @T{(int stepsize)}| @item{@id{LUA_GCSTEP}|
Performs an incremental step of garbage collection, Performs a step of garbage collection.
corresponding to the allocation of @id{stepsize} Kbytes.
} }
@item{@id{LUA_GCISRUNNING}| @item{@id{LUA_GCISRUNNING}|
@ -3321,13 +3331,13 @@ Returns a boolean that tells whether the collector is running
(i.e., not stopped). (i.e., not stopped).
} }
@item{@id{LUA_GCINC} (int pause, int stepmul, stepsize)| @item{@id{LUA_GCINC} (int pause, int stepmul, int stepsize)|
Changes the collector to incremental mode Changes the collector to incremental mode
with the given parameters @see{incmode}. with the given parameters @see{incmode}.
Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}).
} }
@item{@id{LUA_GCGEN} (int minormul, int majormul)| @item{@id{LUA_GCGEN} (int minormul, int minormajor, int majorminor)|
Changes the collector to generational mode Changes the collector to generational mode
with the given parameters @see{genmode}. with the given parameters @see{genmode}.
Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}). Returns the previous mode (@id{LUA_GCGEN} or @id{LUA_GCINC}).
@ -6312,13 +6322,14 @@ gives the exact number of bytes in use by Lua.
@item{@St{step}| @item{@St{step}|
Performs a garbage-collection step. Performs a garbage-collection step.
The step @Q{size} is controlled by @id{arg}. In incremental mode,
With a zero value, that step corresponds to the current step size;
the collector will perform one basic (indivisible) step. the function returns @true if the step finished a collection cycle.
For non-zero values, In generational mode,
the collector will perform as if that amount of memory the step performs a full minor collection or
(in Kbytes) had been allocated by Lua. a major collection,
Returns @true if the step finished a collection cycle. if the collector has scheduled one;
the function returns @true if the step performed a major collection.
} }
@item{@St{isrunning}| @item{@St{isrunning}|
@ -6332,15 +6343,15 @@ This option can be followed by three numbers:
the garbage-collector pause, the garbage-collector pause,
the step multiplier, the step multiplier,
and the step size @see{incmode}. and the step size @see{incmode}.
A zero means to not change that value. A -1 or absent value means to not change that value.
} }
@item{@St{generational}| @item{@St{generational}|
Change the collector mode to generational. Change the collector mode to generational.
This option can be followed by two numbers: This option can be followed by three numbers:
the garbage-collector minor multiplier the garbage-collector minor multiplier,
and the major multiplier @see{genmode}. the minor-major multiplier, and the major-minor multiplier @see{genmode}.
A zero means to not change that value. A -1 or absent value means to not change that value.
} }
} }
@ -9229,6 +9240,9 @@ declare a local variable with the same name in the loop body.
@itemize{ @itemize{
@item{ @item{
There were several changes in the parameters
for the options @St{incremental} and @St{generational}
of the function @Lid{collectgarbage}.
} }
} }
@ -9245,6 +9259,12 @@ it is equivalent to @Lid{lua_closethread} with
@id{from} being @id{NULL}. @id{from} being @id{NULL}.
} }
@item{
There were several changes in the parameters
for the options @Lid{LUA_GCINC} and @Lid{LUA_GCGEN}
of the function @Lid{lua_gc}.
}
} }
} }