Browse Source

First criteria for shifts minor<->major

Roberto Ierusalimschy 1 year ago
parent
commit
925fe8a0f2
8 changed files with 187 additions and 128 deletions
  1. 14 11
      lapi.c
  2. 7 6
      lbaselib.c
  3. 55 26
      lgc.c
  4. 26 22
      lgc.h
  5. 2 1
      lstate.c
  6. 5 4
      lstate.h
  7. 1 1
      lua.c
  8. 77 57
      manual/manual.of

+ 14 - 11
lapi.c

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

+ 7 - 6
lbaselib.c

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

+ 55 - 26
lgc.c

@@ -1205,20 +1205,21 @@ static void correctgraylists (global_State *g) {
 /*
 ** Mark black 'OLD1' objects when starting a new young collection.
 ** 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
-** become old before a major collection.
+** the atomic step. Returns the number of objects that became old.
 */
-static void markold (global_State *g, GCObject *from, GCObject *to) {
+static l_obj markold (global_State *g, GCObject *from, GCObject *to) {
   GCObject *p;
+  l_obj count = 0;
   for (p = from; p != to; p = p->next) {
     if (getage(p) == G_OLD1) {
       lua_assert(!iswhite(p));
       setage(p, G_OLD);  /* now they are old */
-      g->GCmajorminor--;  /* one more old object */
+      count++;  /* one more old object */
       if (isblack(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) {
   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->reallyold = g->old1 = g->survival = 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
 ** atomic step. Then, check whether to continue in minor mode. If so,
 ** sweep all lists and advance pointers. Finally, finish the collection.
 */
 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 *dummy;  /* dummy out parameter to 'sweepgen' */
   lua_assert(g->gcstate == GCSpropagate);
-  g->marked = 0;
   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) */
   }
-  markold(g, g->finobj, g->finobjrold);
-  markold(g, g->tobefnz, NULL);
+  addedold1 += markold(g, g->finobj, g->finobjrold);
+  addedold1 += markold(g, g->tobefnz, NULL);
+
+  atomic(L);  /* will lose 'g->marked' */
 
-  atomic(L);
+  /* keep total number of added old1 objects */
+  g->marked = marked + addedold1;
 
   /* decide whether to shift to major mode */
-  if (g->GCmajorminor <= 0) {  /* ?? */
-    atomic2major(L, g);  /* go to major mode */
+  if (checkminormajor(L, g, addedold1))
     return;  /* nothing else to be done here */
-  }
 
   /* sweep nursery and get a pointer to its last live element */
   g->gcstate = GCSswpallgc;
@@ -1319,7 +1344,8 @@ static void atomic2gen (lua_State *L, global_State *g) {
   sweep2old(L, &g->tobefnz);
 
   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);
 }
 
@@ -1329,7 +1355,7 @@ static void atomic2gen (lua_State *L, global_State *g) {
 ** total number of objects grows 'genminormul'%.
 */
 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) {
   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 == KGC_INC) {  /* entering incremental mode? */
-      if (g->gckind == KGC_GENMAJOR)
-        g->gckind = KGC_INC;  /* already incremental but in name */
-      else
-        enterinc(g);  /* entering incremental mode */
-    }
+    if (newmode == KGC_INC)  /* entering incremental mode? */
+      enterinc(g);  /* entering incremental mode */
     else {
       lua_assert(newmode == KGC_GENMINOR);
       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,
 ** 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) {
   if (g->gckind == KGC_GENMAJOR) {
-    l_obj numobjs = gettotalobjs(g);  /* current count */
-    if (g->marked < numobjs - (numobjs >> 2)) {  /* ?? */
+    l_obj numobjs = gettotalobjs(g);
+    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 */
       setminordebt(g);
       return 0;  /* exit incremental collection */
     }
   }
+  g->GCmajorminor = g->marked;  /* prepare for next collection */
   return 1;  /* stay doing incremental collections */
 }
 
@@ -1634,8 +1666,6 @@ void luaC_step (lua_State *L) {
   if (!gcrunning(g))  /* not running? */
     luaE_setdebt(g, 2000);
   else {
-//printf("> step: %d  %d  %ld %ld -> ", g->gckind, g->gcstate, gettotalobjs(g), g->GCdebt);
-
     switch (g->gckind) {
       case KGC_INC: case KGC_GENMAJOR:
         incstep(L, g);
@@ -1645,7 +1675,6 @@ void luaC_step (lua_State *L) {
         setminordebt(g);
         break;
     }
-//printf("%d  %d  %ld %ld\n", g->gckind, g->gcstate, gettotalobjs(g), g->GCdebt);
   }
 }
 

+ 26 - 22
lgc.h

@@ -161,10 +161,24 @@
 
 /* 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 */
 
@@ -187,27 +201,17 @@
 
 /*
 ** Macros to set and apply GC parameters. GC parameters are given in
-** percentage points, but are stored as lu_byte. To reduce their
-** values and avoid repeated divisions by 100, these macros store
-** the original parameter multiplied by 2^n and divided by 100.
-** To apply them, the value is divided by 2^n (a shift) and then
-** multiplied by the stored parameter, yielding
-** value / 2^n * (original parameter * 2^n / 100), or approximately
-** (value * original parameter / 100).
-**
-** 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%.
+** percentage points, but are stored as lu_byte. To avoid repeated
+** divisions by 100, these macros store the original parameter
+** multiplied by 128 and divided by 100.  To apply them, if it first
+** divides the value by 128 it may lose precision; if it first
+** multiplies by the parameter, it may overflow.  So, it first divides
+** by 32, then multiply by the parameter, and then divides the result by
+** 4.
 */
-#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)
 
 
 /*

+ 2 - 1
lstate.c

@@ -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, gcstepmul, LUAI_GCMUL);
   g->gcstepsize = LUAI_GCSTEPSIZE;
-  setgcparam(g, genmajormul, LUAI_GENMAJORMUL);
   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;
   if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
     /* memory allocation error: free partial state */

+ 5 - 4
lstate.h

@@ -264,16 +264,17 @@ typedef struct global_State {
   TValue l_registry;
   TValue nilvalue;  /* a nil value */
   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 gcstate;  /* state of garbage collector */
   lu_byte gckind;  /* kind of GC running */
   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 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 */
   GCObject *allgc;  /* list of all collectable objects */
   GCObject **sweepgc;  /* current position of sweep in list */

+ 1 - 1
lua.c

@@ -646,7 +646,7 @@ static int pmain (lua_State *L) {
   luai_openlibs(L);  /* open standard libraries */
   createargtable(L, argv, argc, script);  /* create table 'arg' */
   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 (handle_luainit(L) != LUA_OK)  /* run LUA_INIT */
       return 0;  /* error running LUA_INIT */

+ 77 - 57
manual/manual.of

@@ -621,7 +621,8 @@ that is inaccessible from Lua.
 another live object refer to the object.)
 Because Lua has no knowledge about @N{C code},
 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:
@@ -638,8 +639,8 @@ therefore, optimal settings are also non-portable.
 You can change the GC mode and parameters by calling
 @Lid{lua_gc} @N{in C}
 or @Lid{collectgarbage} in Lua.
-You can also use these functions to control
-the collector directly (e.g., to stop and restart it).
+You can also use these functions to control the collector directly,
+for instance to stop or restart it.
 
 }
 
@@ -656,39 +657,36 @@ and the @def{garbage-collector step size}.
 
 The garbage-collector pause
 controls how long the collector waits before starting a new cycle.
-The collector starts a new cycle when the use of memory
-hits @M{n%} of the use after the previous collection.
+The collector starts a new cycle when the number of objects
+hits @M{n%} of the total after the previous collection.
 Larger values make the collector less aggressive.
 Values equal to or less than 100 mean the collector will not wait to
 start a new cycle.
-A value of 200 means that the collector waits for the total memory in use
-to double before starting a new cycle.
+A value of 200 means that the collector waits for
+the total number of objects to double before starting a new cycle.
 The default value is 200; the maximum value is 1000.
 
 The garbage-collector step multiplier
 controls the speed of the collector relative to
-memory allocation,
+object creation,
 that is,
-how many elements it marks or sweeps for each
-kilobyte of memory allocated.
-Larger values make the collector more aggressive but also increase
-the size of each incremental step.
-You should not use values less than 100,
-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.
+how many objects it marks or sweeps for each object created.
+Larger values make the collector more aggressive.
+Beware that values too small can
+make the collector too slow to ever finish a cycle.
+The default value is 300;  the maximum value is 1000.
 
 The garbage-collector step size controls the
 size of each incremental step,
-specifically how many bytes the interpreter allocates
+specifically how many objects the interpreter creates
 before performing a step.
 This parameter is logarithmic:
-A value of @M{n} means the interpreter will allocate @M{2@sp{n}}
-bytes between steps and perform equivalent work during the step.
+A value of @M{n} means the interpreter will create @M{2@sp{n}}
+objects between steps and perform equivalent work during the step.
 A large value (e.g., 60) makes the collector a stop-the-world
 (non-incremental) collector.
-The default value is 13,
-which means steps of approximately @N{8 Kbytes}.
+The default value is 8,
+which means steps of approximately @N{256 objects}.
 
 }
 
@@ -697,31 +695,44 @@ which means steps of approximately @N{8 Kbytes}.
 In generational mode,
 the collector does frequent @emph{minor} collections,
 which traverses only objects recently created.
-If after a minor collection the use of memory is still above a limit,
-the collector does a stop-the-world @emph{major} collection,
+If after a minor collection the number of objects is above a limit,
+the collector shifts to a @emph{major} collection,
 which traverses all objects.
-The generational mode uses two parameters:
-the @def{minor multiplier} and the @def{the major multiplier}.
+The collector will then stay doing major collections until
+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.
 For a minor multiplier @M{x},
-a new minor collection will be done when memory
-grows @M{x%} larger than the memory in use after the previous major
-collection.
+a new minor collection will be done when the number of objects
+grows @M{x%} larger than the number in use just after the last collection.
 For instance, for a multiplier of 20,
-the collector will do a minor collection when the use of memory
-gets 20% larger than the use after the previous major collection.
-The default value is 20; the maximum value is 200.
-
-The major multiplier controls the frequency of major collections.
-For a major multiplier @M{x},
-a new major collection will be done when memory
-grows @M{x%} larger than the memory in use after the previous major
-collection.
+the collector will do a minor collection when the number of objects
+gets 20% larger than the total after the last major collection.
+The default value is 20.
+
+The minor-major multiplier controls the shift to major collections.
+For a multiplier @M{x},
+the collector will shift to a major collection
+when the number of old objects grows @M{x%} larger
+than the total after the previous major collection.
 For instance, for a multiplier of 100,
-the collector will do a major collection when the use of memory
-gets larger than twice the use after the previous collection.
-The default value is 100; the maximum value is 1000.
+the collector will do a major collection when the number of old objects
+gets larger than twice the total after the previous major collection.
+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.
 }
 
-@item{@id{LUA_GCSTEP} @T{(int stepsize)}|
-Performs an incremental step of garbage collection,
-corresponding to the allocation of @id{stepsize} Kbytes.
+@item{@id{LUA_GCSTEP}|
+Performs a step of garbage collection.
 }
 
 @item{@id{LUA_GCISRUNNING}|
@@ -3321,13 +3331,13 @@ Returns a boolean that tells whether the collector is running
 (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
 with the given parameters @see{incmode}.
 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
 with the given parameters @see{genmode}.
 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}|
 Performs a garbage-collection step.
-The step @Q{size} is controlled by @id{arg}.
-With a zero value,
-the collector will perform one basic (indivisible) step.
-For non-zero values,
-the collector will perform as if that amount of memory
-(in Kbytes) had been allocated by Lua.
-Returns @true if the step finished a collection cycle.
+In incremental mode,
+that step corresponds to the current step size;
+the function returns @true if the step finished a collection cycle.
+In generational mode,
+the step performs a full minor collection or
+a major collection,
+if the collector has scheduled one;
+the function returns @true if the step performed a major collection.
 }
 
 @item{@St{isrunning}|
@@ -6332,15 +6343,15 @@ This option can be followed by three numbers:
 the garbage-collector pause,
 the step multiplier,
 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}|
 Change the collector mode to generational.
-This option can be followed by two numbers:
-the garbage-collector minor multiplier
-and the major multiplier @see{genmode}.
-A zero means to not change that value.
+This option can be followed by three numbers:
+the garbage-collector minor multiplier,
+the minor-major multiplier, and the major-minor multiplier @see{genmode}.
+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{
 
 @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}.
 }
 
+@item{
+There were several changes in the parameters
+for the options @Lid{LUA_GCINC} and @Lid{LUA_GCGEN}
+of the function @Lid{lua_gc}.
+}
+
 }
 
 }