GC on OOM

  • From: Denis Golovan <denis.golovan@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Mon, 25 Jul 2016 13:35:38 +0300

Hi all

I stumble on oom in luajit scripts now and then in my code.
It's fixed usually by calling collectgarbage('step') in loops.

However I'd to mitigate the risk of sudden crash/exit when there is
plenty of free memory available, but it has not been garbage-collected
yet.
/ And yes, for me it's much more important not to loose the state vs.
sudden latency spike.

I've made a small test against current HEAD and small patch possibly
fixing the issue. See __gc.lua and gc_on_oom.patch.

Could anybody give opinion on the patch?
Also is there any downside of this approach (besides sudden full gc)?

BR,
Denis
diff --git a/src/lj_gc.c b/src/lj_gc.c
index 7c70746..bd74f70 100644
--- a/src/lj_gc.c
+++ b/src/lj_gc.c
@@ -803,12 +803,29 @@ void lj_gc_barriertrace(global_State *g, uint32_t traceno)
 
 /* -- Allocator ----------------------------------------------------------- */
 
+void *alloc_mem_gc(lua_State *L, void *p, GCSize osz, GCSize nsz)
+{
+  global_State *g = G(L);
+  p = g->allocf(g->allocd, p, osz, nsz);
+  if (p == NULL && nsz > 0)
+    {
+      // allocation failed...
+      //lj_err_mem(L);
+
+      //try again after gc
+      lj_gc_fullgc(L);
+      p = g->allocf(g->allocd, p, osz, nsz);
+    }
+
+  return p;
+}
+
 /* Call pluggable memory allocator to allocate or resize a fragment. */
 void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, GCSize nsz)
 {
   global_State *g = G(L);
   lua_assert((osz == 0) == (p == NULL));
-  p = g->allocf(g->allocd, p, osz, nsz);
+  p = alloc_mem_gc(L, p, osz, nsz);
   if (p == NULL && nsz > 0)
     lj_err_mem(L);
   lua_assert((nsz == 0) == (p == NULL));
@@ -821,7 +838,7 @@ void *lj_mem_realloc(lua_State *L, void *p, GCSize osz, 
GCSize nsz)
 void * LJ_FASTCALL lj_mem_newgco(lua_State *L, GCSize size)
 {
   global_State *g = G(L);
-  GCobj *o = (GCobj *)g->allocf(g->allocd, NULL, 0, size);
+  GCobj *o = (GCobj *)alloc_mem_gc(L, NULL, 0, size);
   if (o == NULL)
     lj_err_mem(L);
   lua_assert(checkptrGC(o));
@@ -844,4 +861,3 @@ void *lj_mem_grow(lua_State *L, void *p, MSize *szp, MSize 
lim, MSize esz)
   *szp = sz;
   return p;
 }
-

collectgarbage("setstepmul",20)
collectgarbage("setpause",60)

ffi=require('ffi')
ffi.cdef("void* malloc(size_t size); void free(void* ptr);")

while true do
  local size=10
  local arr = ffi.gc(ffi.C.malloc(size), ffi.C.free)
end

print "ok"

Other related posts: