Lua GC 不会自动收集

Lua GC is not collecting automatically

提问人:Rioni 提问时间:11/16/2023 更新时间:11/16/2023 访问量:21

问:

我对 lua 有点陌生,尽管我已经在其他时候使用过这种语言,并且我已经阅读了很多关于它的文章。现在,我第二次使用它作为 C++11 项目的脚本语言。我第一次使用它时,我的 GC 出现了问题,但我决定每隔几秒钟就给lua_gc打电话一次。

现在,我想避免这种情况,以压缩性能并避免内存泄漏。我有一个简单的虚拟测试示例,使用 LuaJit 和 luabridge 来执行 lua 函数 twiice。

我知道必须手动释放用户数据对象,但同样,即使我没有将表返回到 C++ 中的 luaref 中的缓存,它仍然保留在内存中。

Luajit 和 C++ 代码都是使用 MSVC 编译的

法典:

#include <lua.hpp>
#include <iostream>
#include <chrono>
#include "LuaBridge/LuaBridge.h"
#include "LuaBridge/detail/LuaRef.h"
#include <thread>

const int prime_count = 1000000;

void setJITStatus(lua_State* L, bool enabled) {
    lua_getglobal(L, "jit");
    lua_getfield(L, -1, enabled ? "on" : "off");
    lua_pcall(L, 0, 0, 0);
    lua_pop(L, 1);
}

bool isJITActive(lua_State* L) {
    lua_getglobal(L, "jit");
    lua_getfield(L, -1, "status");

    if (lua_pcall(L, 0, 1, 0) == LUA_OK) {
        bool jitActive = lua_toboolean(L, -1) != 0;
        lua_pop(L, 2);
        return jitActive;
    }
    else {
        std::cerr << "Error when calling jit.status()." << std::endl;
        return false;
    }
}

void measureLuaFunction(lua_State* L, const char* luaCode, const char* functionName) {
    if (luaL_dostring(L, luaCode) == LUA_OK) {
        luabridge::LuaRef luaFunc = luabridge::getGlobal(L, functionName);
        
        // 3 MB in memory before this call
        if (luaFunc.isFunction()) {
            auto start = std::chrono::high_resolution_clock::now();
            luaFunc(prime_count);

            // I do another call to the func to see if the memory allocated by the first one is freed while the new one executes, but nop :)

            luaFunc(prime_count);
            
            // 21 MB in memory after the second call ends (won't get released unless I call lua_gc)

            auto stop = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);

            std::cout << "Execution time: " << duration.count() << " milliseconds" << "\n";
        }
        else {
            std::cerr << "Function '" << functionName << "' is not callable." << std::endl;
        }
    }
    else {
        std::cerr << "Error at executing lua code." << std::endl;
    }
}

int main() {
    lua_State* L = luaL_newstate();
    luaL_openlibs(L);

    const char* luaCode = R"lua(
        function isPrime(number)
            if number <= 1 then
                return false
            end
            for i = 2, math.sqrt(number) do
                if number % i == 0 then
                    return false
                end
            end
            return true
        end

        function calculatePrimes(count)
            local primes = {}
            local i = 2
            while #primes < count do
                if isPrime(i) then
                    table.insert(primes, i)
                end
                i = i + 1
            end
            -- removing the return statement doesn't have any effect
            -- return primes
        end
    )lua";

    // Not sure if I should do this, default values of lua vm should be fine but I had to try
    // Right now that commented line of code doesn't seem to have an effect in this test, so that's why it's commented
    // luaL_dostring(L, "jit.opt.start('maxmcode=2048', 'maxtrace=2048')");

    std::cout << "\nIs Jit Active (0 no, 1 yes): " << isJITActive(L) << std::endl;
    measureLuaFunction(L, luaCode, "calculatePrimes");
    
    // This line solves the problem, but brings others
    // lua_gc(L, LUA_GCCOLLECT, 0);

    std::cout << "Closing...\n";

    // Thread sleep time to see if the luz gc is able to do something on its own
    std::this_thread::sleep_for(std::chrono::seconds(5));
    
    lua_close(L);

    return 0;
}

现在,在这项研究之后,我不确定这是否正常,我只是不理解lua,或者我是否做错了什么。如有必要,我可以将整个项目共享为zip文件。

尝试过的东西:

  • 从项目中删除 luabridge 并仅使用 lua 仍然会遇到问题

  • 删除 lua 代码中的 return 语句并不能解决此问题

  • 删除表并创建局部变量可以解决问题(它使代码无用,但嘿,至少我知道那些局部变量在超出范围时确实被清理了)

lua 垃圾回收 luajit luabridge

评论

0赞 ESkri 11/18/2023
Lua GC 会自动收集。但它根据自己的决定完成工作。当然,它不符合您对何时收集的期望。这就是为什么您可以按需收集的原因。所以,我不明白你要解决的问题是什么。lua_gc

答: 暂无答案