From 626cf0581bc214722033d61c69d5db9e51e53465 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 9 Jul 2018 14:22:09 -0300 Subject: [PATCH] Generational mode may wait longer after a major collection When Lua is building large long-duration structures, frequent small minor collections just waste time. Trying to avoid this, the collector will do a larger pause after a major collection when it does not collect enough garbage (which is a hint that memory is being used for long-lasting objects). --- lgc.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/lgc.c b/lgc.c index b0e3c363..fb02f015 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.253 2018/03/16 14:22:09 roberto Exp roberto $ +** $Id$ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -12,6 +12,7 @@ #include #include + #include "lua.h" #include "ldebug.h" @@ -1004,6 +1005,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** ======================================================= */ +static void setpause (global_State *g); + /* mask to erase all color bits, not changing gen-related stuff */ #define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS)) @@ -1275,21 +1278,35 @@ static void fullgen (lua_State *L, global_State *g) { ** than last major collection (kept in 'g->GCestimate'), does a major ** collection. Otherwise, does a minor collection and set debt to make ** another collection when memory grows 'genminormul'% larger. +** When it does a major collection, it then checks whether it could +** reclaim at least ?? memory. If not, it sets a long pause for the +** next collection. (Therefore, the next collection will be a major +** one, too.) ** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; ** in that case, always do a minor collection. */ static void genstep (lua_State *L, global_State *g) { - lu_mem majorbase = g->GCestimate; - int majormul = getgcparam(g->genmajormul); - if (g->GCdebt > 0 && - gettotalbytes(g) > (majorbase / 100) * (100 + majormul)) { + lu_mem majorbase = g->GCestimate; /* memory after last major collection */ + lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); + lu_mem memnew = gettotalbytes(g); + if (g->GCdebt > 0 && memnew > majorbase + majorinc) { fullgen(L, g); + memnew = gettotalbytes(g); + if (memnew < majorbase + (majorinc / 2)) { + /* collected at least half of memory growth since last major + collection; go back to minor collections */ + luaE_setdebt(g, -(cast(l_mem, (memnew / 100)) * g->genminormul)); + } + else { + /* memory seems to be growing; do a long wait for next (major) + collection */ + setpause(g); + } } else { - lu_mem mem; youngcollection(L, g); - mem = gettotalbytes(g); - luaE_setdebt(g, -(cast(l_mem, (mem / 100)) * g->genminormul)); + memnew = gettotalbytes(g); + luaE_setdebt(g, -(cast(l_mem, (memnew / 100)) * g->genminormul)); g->GCestimate = majorbase; /* preserve base value */ } }