Using embeded lua 5.4.8 ( cannot test 5.5.0 now )...
I have a C function published into lua, stripping irrelevant details looks like:
int mp_loadfilex(lua_State * L) {
auto name = luaL_checkstring(L,1);
int fd = ::open(name, O_RDONLY | O_NOATIME, 0);
struct stat st;
::fstat(fd, &st);
auto mm = ::mmap(nullptr, st.st_size, PROT_READ,
MAP_SHARED | MAP_POPULATE, fd, 0);
auto mode = luaL_optstring(L,2, nullptr);
int status = luaL_loadbufferx(L,(const char *)mm, st.st_size, name, mode);
::munmap(mm, st.st_size);
::close(fd);
return 1;
}
Simple and easy, implement loadfile using mmap ( there is some extra code and reasons to go this way ).
Function works well but when benchmarking it by running it in a loop and comparing with loadfile my mem usage skyrocketed until I hit the Linux OOM killer.
It did not fail when doing a 100 repetitions loop ten times, but failed on a 1000 reps loop.
Test file is just returning a big table with several subtables,
wc-l kk*
35092 217644 3285233 kk.lua
1168 3853 799364 kk.luacs
I use the cs ( compiled stripped ) version, which according to luac has
main <kk.lua:0,0> (103696 instructions at 0x5c27e4036cc0)
0+ params, 7 slots, 1 upvalue, 0 locals, 28958 constants, 0 functions
Calling loadfile does not fail. Calling collectgarbage in the loop fix it, as does executing the result of loadfilex or just creating an empty table in the loop. Or doing a print.
Taking a look at 5.4.8 lvm.c and a couple other places lead me to think lua does not take into account the memory usage of the lua_load created function. Can this be true ?
If so, which would be the recommended way to avoid it? It will probably not happen in real code, where the call will always be evaluated and surrounded by lots of lua code, but I would prefer to put a properly commented lua_newtable, or lua_gc(LUAGC_STEP) instruction inside the C function for future proofing.
Francisco Olarte.