Skip to content

Commit

Permalink
Fixed high memory usage caused by ropes & substrings
Browse files Browse the repository at this point in the history
  • Loading branch information
MCJack123 committed Jan 8, 2024
1 parent c116882 commit e9a93c2
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 41 deletions.
4 changes: 1 addition & 3 deletions src/lapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -599,13 +599,11 @@ LUA_API const char *lua_pushsubstring (lua_State *L, int idx, size_t start, size
}
if (ss != NULL) break;
if (nextsscluster(cluster) == NULL) { /* need new cluster? */
olddebt = g->GCdebt;
next = luaM_newvector(L, SUBSTR_CLUSTER_SIZE, TString);
g->GCdebt = olddebt;
memset(next, 0, SUBSTR_CLUSTER_SIZE * sizeof(TString));
nextsscluster(cluster) = next; /* chain next cluster in list */
nextsscluster(next) = NULL; /* ensure next pointer is NULL */
clusterid(next) = clusterid(cluster) + 1; /* set cluster number */
rawclusterid(next) = (clusterid(cluster) + 1) | (g->currentwhite & bitmask(WHITE0BIT) ? 0 : ~CLUSTERID_MASK); /* set cluster number */
((bitmap_unit*)next)[BITMAP_SKIP] = 0xFFFF; /* always mark first entry as used by bitmap */
nextsscluster(cluster) = next;
}
Expand Down
29 changes: 17 additions & 12 deletions src/lgc.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,26 +525,27 @@ static lu_mem traversestack (global_State *g, lua_State *th) {


static int traverserope (global_State *g, TString *r) {
int size = sizeof(TString);
if (r->tsr.left) {
if (r->tsr.left)
markobject(g, r->tsr.left);
//size += sizeof(TString);
}
if (r->tsr.right) {
if (r->tsr.right)
markobject(g, r->tsr.right);
//size += sizeof(TString);
}
if (r->tsr.res) {
if (r->tsr.res)
markobject(g, r->tsr.res);
//size += sizeof(TString);
if ((rawclusterid(r->tsr.cluster) & ~CLUSTERID_MASK ? 1 : 0) != (g->currentwhite & bitmask(WHITE0BIT) ? 1 : 0)) {
rawclusterid(r->tsr.cluster) = clusterid(r->tsr.cluster) | (g->currentwhite & bitmask(WHITE0BIT) ? ~CLUSTERID_MASK : 0);
return sizeof(TString);
}
return size;
return 0;
}


static int traversesubstr (global_State *g, TString *ss) {
markobject(g, ss->tss.str);
return sizeof(TString);
if ((rawclusterid(ss->tss.cluster) & ~CLUSTERID_MASK ? 1 : 0) != (g->currentwhite & bitmask(WHITE0BIT) ? 1 : 0)) {
rawclusterid(ss->tss.cluster) = clusterid(ss->tss.cluster) | (g->currentwhite & bitmask(WHITE0BIT) ? ~CLUSTERID_MASK : 0);
return sizeof(TString);
}
return 0;
}


Expand Down Expand Up @@ -1089,8 +1090,12 @@ static lu_mem singlestep (lua_State *L) {
global_State *g = G(L);
switch (g->gcstate) {
case GCSpause: {
TString* cluster;
/* start to count memory traversed */
g->GCmemtrav = g->strt.size * sizeof(GCObject*);
g->GCmemtrav = g->strt.size * sizeof(GCObject*) +
g->ropestacksize * sizeof(TString*) +
ROPE_CLUSTER_SIZE * sizeof(TString) +
SUBSTR_CLUSTER_SIZE * sizeof(TString); /* "static" blocks */
lua_assert(!isgenerational(g));
restartcollection(g);
g->gcstate = GCSpropagate;
Expand Down
10 changes: 2 additions & 8 deletions src/lstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ static void f_luaopen (lua_State *L, void *ud) {
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaS_fix(g->memerrmsg); /* it should never be collected */
/* allocate rope and substring clusters */
olddebt = g->GCdebt; /* don't count debt of these, they are never found by GC */
g->ropestack = luaM_newvector(L, g->ropestacksize, TString *);
g->ropeclusters = luaM_newvector(L, ROPE_CLUSTER_SIZE, TString);
memset(g->ropeclusters, 0, ROPE_CLUSTER_SIZE * sizeof(TString));
Expand All @@ -213,9 +212,6 @@ static void f_luaopen (lua_State *L, void *ud) {
((unsigned long*)g->ssclusters)[BITMAP_SKIP] = 0xFFFF; /* always mark first entry as used by bitmap */
g->ssfreecluster = g->ssclusters;
memset(g->allowedcfuncs, 0, sizeof(g->allowedcfuncs)); /* set all funclists to NULL */
/* mark new allocations as compensated & reset debt */
//g->totalbytes += g->GCdebt - olddebt;
g->GCdebt = olddebt;
g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
luai_userstateopen(L);
Expand Down Expand Up @@ -257,19 +253,17 @@ static void close_state (lua_State *L) {
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
olddebt = g->GCdebt;
luaM_freearray(L, g->ropestack, g->ropestacksize);
while (cluster != NULL) {
next = *(TString**)cluster;
luaM_free(L, cluster);
luaM_freemem(L, cluster, ROPE_CLUSTER_SIZE * sizeof(TString));
cluster = next;
}
while (sscluster != NULL) {
ssnext = *(TString**)sscluster;
luaM_free(L, sscluster);
luaM_freemem(L, sscluster, SUBSTR_CLUSTER_SIZE * sizeof(TString));
sscluster = ssnext;
}
g->GCdebt = olddebt;
//lua_assert(gettotalbytes(g) == sizeof(LG));
if (g->lockstate) lua_unlock(L);
_lua_freelock(g->lock);
Expand Down
33 changes: 16 additions & 17 deletions src/lstring.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,11 @@ TString *luaS_concat (lua_State *L, TString *l, TString *r) {
}
if (rope != NULL) break;
if (nextropecluster(cluster) == NULL) { /* need new cluster? */
olddebt = g->GCdebt;
next = luaM_newvector(L, ROPE_CLUSTER_SIZE, TString);
g->GCdebt = olddebt;
memset(next, 0, ROPE_CLUSTER_SIZE * sizeof(TString));
nextropecluster(cluster) = next; /* chain next cluster in list */
nextropecluster(next) = NULL; /* ensure next pointer is NULL */
clusterid(next) = clusterid(cluster) + 1; /* set cluster number */
rawclusterid(next) = (clusterid(cluster) + 1) | (g->currentwhite & bitmask(WHITE0BIT) ? 0 : ~CLUSTERID_MASK); /* set cluster number */
((bitmap_unit*)next)[BITMAP_SKIP] = 0xFFFF; /* always mark first entry as used by bitmap */
nextropecluster(cluster) = next;
}
Expand All @@ -239,20 +237,21 @@ TString *luaS_build (lua_State *L, TString *rope) {
TString *s;
TString **stack;
TString *orig = rope;
l_mem olddebt;
int freemem = 0;
void* alloc_ud;
if (rope->tsr.tt == LUA_TSHRSTR || rope->tsr.tt == LUA_TLNGSTR || rope->tsr.tt == LUA_TSUBSTR) return cast(TString *, rope);
if (rope->tsr.res || rope->tsr.left == NULL || rope->tsr.right == NULL) return rope->tsr.res;
if (rope->tsr.len >= ROPE_ALLOC_MIN_SIZE) buffer = cur = luaM_newvector(L, rope->tsr.len, char);
else buffer = cur = luaZ_openspace(L, &G(L)->buff, rope->tsr.len);
if (rope->tsr.len >= ROPE_ALLOC_MIN_SIZE) {
buffer = cur = G(L)->frealloc(G(L)->ud, NULL, 0, rope->tsr.len * sizeof(char));
freemem = 1;
} else buffer = cur = luaZ_openspace(L, &G(L)->buff, rope->tsr.len);
stack = G(L)->ropestack;
do {
int b = 0;
while (rope->tsr.left->tsr.tt == LUA_TROPSTR && rope->tsr.left->tsr.res == NULL) {
if (stack - G(L)->ropestack == G(L)->ropestacksize - 1) {
TString **oldbase = G(L)->ropestack;
olddebt = G(L)->GCdebt;
luaM_reallocvector(L, G(L)->ropestack, G(L)->ropestacksize, G(L)->ropestacksize + G(L)->ropestacksize, TString *);
G(L)->GCdebt = olddebt;
stack = G(L)->ropestack + (stack - oldbase);
G(L)->ropestacksize += G(L)->ropestacksize;
}
Expand Down Expand Up @@ -287,7 +286,9 @@ TString *luaS_build (lua_State *L, TString *rope) {
rope = rope->tsr.right;
} while (stack >= G(L)->ropestack);
s = luaS_newlstr(L, buffer, cur - buffer);
if (orig->tsr.len >= ROPE_ALLOC_MIN_SIZE) luaM_free(L, buffer);
if (freemem) {
G(L)->frealloc(G(L)->ud, buffer, orig->tsr.len * sizeof(char), 0);
}
orig->tsr.res = s;
orig->tsr.left = orig->tsr.right = NULL; /* release left & right nodes (we don't need them anymore) */
/* mark the string as black so it doesn't accidentally get freed */
Expand Down Expand Up @@ -318,7 +319,6 @@ static void freeropeclusters (lua_State *L) {
TString *cluster, *last = NULL;
bitmap_unit *bitmap;
int i, empty, full, kept = 1, setfree = 0;
l_mem olddebt;
for (cluster = G(L)->ropeclusters; cluster != NULL; last = cluster, cluster = nextropecluster(cluster)) {
bitmap = (bitmap_unit*)cluster + BITMAP_SKIP;
empty = (bitmap[0] & ~(bitmap_unit)(0xFFFF)) == 0; /* ignore first entry use bit */
Expand All @@ -334,14 +334,14 @@ static void freeropeclusters (lua_State *L) {
if (empty) { /* entire cluster unused? */
if (kept) {
kept--; /* leave one empty cluster allocated */
setfree = 1;
G(L)->ropefreecluster = cluster;
} else {
/* unlink and free cluster */
nextropecluster(last) = nextropecluster(cluster);
if (G(L)->ropefreecluster == cluster)
G(L)->ropefreecluster = nextropecluster(cluster);
olddebt = G(L)->GCdebt;
luaM_free(L, cluster);
G(L)->GCdebt = olddebt;
luaM_freemem(L, cluster, ROPE_CLUSTER_SIZE * sizeof(TString));
cluster = last;
}
} else if (full && !setfree) {
Expand All @@ -355,7 +355,6 @@ static void freessclusters (lua_State *L) {
TString *cluster, *last = NULL;
bitmap_unit *bitmap;
int i, empty, full, kept = 1, setfree = 0;
l_mem olddebt;
for (cluster = G(L)->ssclusters; cluster != NULL; last = cluster, cluster = nextsscluster(cluster)) {
bitmap = (bitmap_unit*)cluster + BITMAP_SKIP;
empty = (bitmap[0] & ~(bitmap_unit)(0xFFFF)) == 0; /* ignore first entry use bit */
Expand All @@ -371,14 +370,14 @@ static void freessclusters (lua_State *L) {
if (empty) { /* entire cluster unused? */
if (kept) {
kept--; /* leave one empty cluster allocated */
setfree = 1;
G(L)->ssfreecluster = cluster;
} else {
/* unlink and free cluster */
nextsscluster(last) = nextsscluster(cluster);
if (G(L)->ssfreecluster == cluster)
G(L)->ssfreecluster = nextsscluster(cluster);
olddebt = G(L)->GCdebt;
luaM_free(L, cluster);
G(L)->GCdebt = olddebt;
luaM_freemem(L, cluster, SUBSTR_CLUSTER_SIZE * sizeof(TString));
cluster = last;
}
} else if (full && !setfree) {
Expand Down
4 changes: 3 additions & 1 deletion src/lstring.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
#define SUBSTR_CLUSTER_SIZE ((sizeof(TString) * 16 - sizeof(void*) * 2) * 8)
#define BITMAP_UNIT_SIZE (sizeof(bitmap_unit) * 8)
#define BITMAP_SKIP (sizeof(void*) / sizeof(bitmap_unit) * 2)
#define CLUSTERID_MASK LONG_MAX

#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char))

#define sizeudata(u) (sizeof(union Udata)+(u)->len)

#define clusterid(l) (*(bitmap_unit*)((void**)(l) + 1))
#define clusterid(l) (*(bitmap_unit*)((void**)(l) + 1) & CLUSTERID_MASK)
#define rawclusterid(l) (*(bitmap_unit*)((void**)(l) + 1))
#define nextropecluster(l) (*(TString**)(l))
#define nextsscluster(l) (*(TString**)(l))

Expand Down

0 comments on commit e9a93c2

Please sign in to comment.