我一直在使用 LuaPlus 来使用脚本语言公开模块的功能。为此,LuaPlus 真的很棒,但我坚持清理我的暴露对象,因为我不知道如何处理删除代表我的 c++ 对象的 lua 对象,所以我可以正确释放 c++ 资源。
我正在使用 lua 表和元表来表示 cpp 对象,将指向 cpp 对象的指针作为表的 lightuserdata 参数“__object”传递,所以我可以做类似的事情
function foo()
local p = MyCppObject:new() //Create a cpp object and bind it to a table+metatable
p:do_something() //Correctly calls the cpp member function do_something
....
(exits scope) //No more references to p, so p is deleted.
end
函数退出后(或一段时间后),我希望调用元表方法 "__gc",我在其中调用内部 cpp 对象的删除,但我没有看到我的 cpp 回调被调用全部。我尝试使用 lua 的函数collectgarbage强制垃圾收集,多次调用我的函数来强制 lua 收集我的对象,但我看不到我的回调正在执行。最重要的是,我看到调用 collectgarbage("count") 的结果有时会减少,因此某些内容会在某处被删除,但我不知道是什么。我检查了 lua 文档,但我看不出我做错了什么:(
任何评论表示赞赏!谢谢!
更新:添加了 c++ 代码端 + 添加了 Mud 指出的本地 + 我的测试示例
我创建了我的程序的这个小样本。LuaShell 对象只是状态的包装器 + 读取命令行并执行从 std::cin 读取的字符串的循环
#include <iostream>
#include "LuaPlus.h"
class Point
{
private:
int x_,y_;
public:
Point(): x_(0), y_(0){}
Point(int a, int b): x_(a), y_(b){}
~Point() {std::cout << "Point "<< x_ << ","
<< y_ << "being deleted" << std::endl;}
int x() const { return x_;}
int y() const { return y_;}
};
LuaPlus::LuaObject metatable;
int new_point( LuaPlus::LuaState* state)
{
LuaPlus::LuaStack args(state);
//std::cout << "Creating point!!" << std::endl;
float x = 0, y = 0;
if ( args.Count() == 3)
{
if (args[2].IsNumber() && args[3].IsNumber())
{
x = args[2].GetFloat();
y = args[3].GetFloat();
}
}
Point* p = new Point(x,y);
LuaPlus::LuaObject lua_obj = state->CreateTable();
lua_obj.SetLightUserData("__object", p);
lua_obj.SetMetaTable( metatable );
return 1;
}
int my_gc_event( LuaPlus::LuaState* state)
{
std::cout << "Calling gc_event from lua" << std::endl;
return 0;
}
int main()
{
/* Creating the object that holds the Lua interpreter as well as
* the command line
*/
LuaShell::Shell shell(true);
LuaPlus::LuaObject globals = shell.get_state()->GetGlobals();
metatable = globals.CreateTable("PointMetaTable");
metatable.SetObject("__index", metatable);
metatable.Register("new", new_point);
metatable.Register("__gc",my_gc_event);
metatable.RegisterObjectDirect("x", (Point*)0 ,&Point::x);
metatable.RegisterObjectDirect("y", (Point*)0 ,&Point::y);
globals.SetObject("Point", metatable);
//Get into the read-command-line-until-quit loop.
shell.run();
return 0;
}
在 lua 方面,我运行它来测试。
? k,b = collectgarbage("count") print (k*1024)
> 33761
? for it=1,1000000 do foo() end
? k,b = collectgarbage("count") print (k*1024)
> 75315
? collectgarbage()
? k,b = collectgarbage("count") print (k*1024)
> 32363
如您所见,根据 lua 运行时有“一些”垃圾收集,但是当我看到我的进程的顶级报告时,内存只会上升,而不会下降。此外,我从来没有看到来自点析构函数的消息(预计因为我并没有真正调用它)或来自“my_gc_event”内部的消息(意外,因为我认为它在收集垃圾工作期间的某个时候被调用)。
再次感谢!