4

我有一个使用 Lua 运行的 C 程序。

虽然我尝试使用 lua_gc() 来获取和控制 Lua 的内存使用,但 C 进程的内存使用仍然很高。尽管 Lua 说它只使用 4MB 内存,但 C 进程使用超过 150MB 内存。

我也尝试使用我的 l_alloc() 函数来跟踪 Lua 内存分配,但结果与调用 lua_gc(LUA_GCCOUNT) 和 lua_gc(LUA_GCCOUNTB) 告诉 Lua 的内存使用情况相同。

调用 lua_close() 关闭 Lua 环境后,进程内存down,看起来还不错。因此,我认为“丢失的记忆”仍然是由 Lua 而不是 C 程序控制的。

这是示例 C 代码。它创建一个 Lua 环境,调用 Lua 函数来清除数据,然后检查内存使用情况。

int main()
{
    int rc;
    uint64_t gc_mem_usage;

    lua_State* Lua = luaL_newstate();
    luaL_openlibs(Lua);

    lua_gc(Lua, LUA_GCSTOP, 0);
    luaL_dofile(Lua, "test.lua");

    gc_mem_usage = ((uint64_t)lua_gc(Lua, LUA_GCCOUNT, 0) << 10) + lua_gc(Lua, LUA_GCCOUNTB, 0);
    printf("Lua mem usage: [%" PRIu64 "] Bytes\n", gc_mem_usage);

    lua_getglobal(Lua, "command_handler");
    lua_pushstring(Lua, "CC");
    rc = lua_pcall(Lua, 1, 0, 0);
    if (rc != 0 ) {
        printf("function error\n");
        return;
    }

    lua_settop(Lua, 0);

    // do full gc
    lua_gc(Lua, LUA_GCCOLLECT, 0);
    lua_gc(Lua, LUA_GCCOLLECT, 0); // I don't know why it has different result by calling full gc twice
    sleep(1);

    printf("-------------After GC ----------------------\n");
    gc_mem_usage = ((uint64_t)lua_gc(Lua, LUA_GCCOUNT, 0) << 10) + lua_gc(Lua, LUA_GCCOUNTB, 0);
    printf("Lua mem usage: [%" PRIu64 "] Bytes\n", gc_mem_usage);

    // infinite-loop
    while(1);
}

Lua 示例代码:

local abc = {}

function command_handler(cmd)
    if (cmd == "CC") then
        abc = {}
    end
end

for i =0, 2000000 do
    abc[i] = "ABC" .. i .. "DEF"
end

输出:

Lua mem usage: [204913817] Bytes
-------------After GC ----------------------
Lua mem usage: [4219342] Bytes

输出告诉我在 GC 之后 Lua 内存使用量下降了,但是通过不断检查顶部,这个 C 进程的内存使用量仍然很高(193.7MB)。

 PID MINFLT MAJFLT      VSTEXT  VSIZE  RSIZE  VGROW  RGROW  MEM CMD     1/1
4622      1      0          3K 193.7M 183.9M     0K     4K  18% a.out

有什么解决方案可以减少 C 进程内存使用量吗?

我的环境是在 Ubuntu/CentOS 中运行的 Lua 5.1.4。

4

1 回答 1

4

Lua faithfully frees unreachable objects by calling the supplied deallocation function (by default realloc(block, 0)). It looks like libc allocator is struggling to return unused memory, possibly due to high fragmentation. Looking at the strace output (I've got roughly the same numbers with Lua 5.1.4 on 64-bit Debian 6), C runtime chooses to allocate using brk with small increments, but no deallocation (calling brk with lower value) follows. However, if you insert malloc_trim(M_TOP_PAD) before entering infinite loop, you'll see in the top output that resident size drops drastically to ~5M and strace reveals that data segment was indeed trimmed with brk. Using custom allocator (e.g. pool-based) or tuning malloc parameters will probably help in this situation.

于 2013-08-08T06:57:19.813 回答