如何使用Lua跟踪内存泄漏/被遗弃的对象?

4

我正在使用Lua的cocos2d-x进行开发。最近,我使用了Instruments工具,并发现有一些被丢弃的内存:

cocos2d-x在其自己的autorelease pool中对对象执行释放操作,但我仍然有来自Lua的引用。

如何确定何时产生这些引用?

我需要释放该内存以避免留下未使用的内存分配。我所能想到的唯一方法是使用一些Lua调试器来查看非nil的Lua指针。

如果我只知道哪个Lua引用持有该指针,那么我可以手动释放它。


如果Cocos2D-X能够自行释放对象,那么你不应该直接给Lua代码引用这些对象。相反,当Lua获得访问这些对象的权限时,它应该有一种告诉Cocos2D-X在Lua使用完它们之前不要释放它们的方法。你试图倒推解决问题,等到问题已经出现了再去修复它。 - Nicol Bolas
你说得对。我已经收到了一堆能够实现这个功能的代码,我想从lua层面释放对象,以便给cocos2d-x触发它们的释放。我现在有一些废弃的内存,我想让它更加高效。 - pro_metedorr
2个回答

3

您的问题有点奇怪。但是我理解您的Lua脚本引用了在外部代码中分配的对象,只要Lua保留这些引用,外部代码就不会释放这些资源,而您认为应该释放这些资源。

首先,您应该检查您的Lua接口代码是否使用元方法来正确清理引用。也就是说,当Lua使用对象引用完成后,附有元方法(__gc)将通知外部代码Lua已经完成该对象。

在此文章的其余部分中,我假设这个代码存在并正常运行。您应该自己验证这一点。

假定上述内容属实,则您看到的情况可能有以下两个原因:

  1. 您的Lua代码已经完成了对所有引用的使用,但尚未清理它们。我的意思是指Lua脚本不再具有任何本地变量、全局变量等引用。在这种情况下,发生的情况是Lua的垃圾收集器尚未运行和清理干净。所以您需要使用lua_gc(L, LUA_GCCOLLECT, 0); 方法清理它们。如果是这种情况,在运行此函数之后,所有来自Lua的引用都应该已经被清理掉了。

  2. 您的Lua代码仍然保留了对外部对象的引用。

处理第二种情况很困难。它是Lua代码的责任。当需要引用时,它应该存储引用,然后在以后忘记这些引用。我的意思是不要将值存储在非本地变量中(通过“非本地”,我也意味着避免由嵌套函数定义使用的本地变量)。

没有办法查找仍存在这些引用的位置;毕竟,Lua值不一定有一个名称。此外,Lua确实没有给您一种方法来迭代lua_State中的每个可能的变量。即使有,毫无疑问也没有一种方式可以简单地清除这些引用。毕竟,Lua代码仍然可以“触摸”它们。如果您把它们清空,Lua代码会在尝试与这些对象通信时崩溃。因此,即使您能做到想要的事情,也会适得其反。

我建议采用以下三种方法之一来处理此问题:

  1. 在编写脚本时要严格控制自己,确保你知道所有非Lua对象的存储位置。一定要确保这些对象在应该释放时得到了释放。记住你放置这些外部对象的位置,并确保它们能够按时释放。所谓“释放”,就是简单地用nil覆盖其值。

  2. 在脚本和源代码之间建立隔离层。与其直接将Lua指针传递给Cocos2D-X对象,不如将其传递给一个特殊对象的指针,该对象可能包含对Cocos2D-X对象的引用。这样,你可以通过告诉控制对象放弃其引用来直接控制这些对象何时被释放。如果Lua调用一个空的控制对象,那么函数将返回……一些无害的东西(以避免崩溃)。显然,Lua应该有一个函数来判断它是否为有效的控制对象。

  3. 在Lua里做任何想做的事情,但是当需要释放资源时,就销毁整个Lua状态。你目前的方法非常细粒度。Lua创建一些资源,然后Lua决定它们什么时候消失。更加严格的资源管理方案是,Lua脚本加载一些资源并引用这些资源。但当需要销毁所有这些资源时,只需关闭lua_State本身的lua_close。这将释放所有引用,从而释放这些资源。问题解决了。


感谢您的建议。下一步操作中将会考虑到它们。现在,我需要从现有的 Lua 源代码中恢复项目,因此我需要一个良好的调试器来查看可能保存引用的指针。在这件事情发生之前,进行“Lua 智能指针”替换可能是一件好事。 - pro_metedorr

0

我也遇到了这个问题。

不幸的是,尽管Lua脚本引擎有对象的引用,Cocos2d-x仍然可以销毁CCObjects。看起来绑定并不完美。

您可以通过在静态包中创建一个CCNode,然后将另一个CCNode添加到场景中,然后将其删除(触发清理),然后等待一帧更新来测试此功能。尽管具有有效的lua引用,原始的CCNode对象将消失,并且尝试在Lua中调用其方法将抛出错误,尽管对象~ = nil。

您可以通过创建一个CCMutableArray_CCObject__对象并将CCObjects添加到其中来解决此问题。这将增加这些对象的引用计数,并且CCMutableArray_CCObject__将不会被垃圾回收,除非也垃圾回收lua引用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接