提问人:Rioni 提问时间:11/16/2023 更新时间:11/16/2023 访问量:21
Lua GC 不会自动收集
Lua GC is not collecting automatically
问:
我对 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_gc