引子
最近用机器人做NPC的压力测试,突然发现一台机器能支持的机器人数量剧减,而且运行一段时间后整台机器直接内存耗光死机.经过观察,发现1个机器人在运行一段时间之后内存能占用到120M之多,而且还在不断增加,同时内存无法手动回收.
以前1个机器人大概消耗10M-20M的内存,这次的消耗明显异常了,所以初步判断逻辑上存在lua对象泄漏:在某些没有注意到的地方长期引用着不再使用的lua对象,导致这些对象无法被gc.
为了解决这个问题,google到一篇相似问题的文章,lua内存泄漏查证.文章的大概思路就是:
- 资源跟踪,定位哪些资源泄漏
- 引用检索,查找泄漏的资源被哪个模块引用
资源跟踪
定义:将应用中分配的lua对象添加到一个弱表中.执行完整的gc后,还能从弱表中索引到的对象表示它还在别的地方被引用着,可能是正常的引用,也可能是一处内存泄漏.
我使用了一个弱键表,该表以要跟踪的lua对象为键,该对象的描述信息为值.其中的描述信息包含了对象描述和对象创建时间两项.对象描述用于区别不同的跟踪对象;创建时间则用来在打印弱表的时候判断对象的存活时间是否合理.
我定义的接口是:function TraceMem(obj, description);
虽然机器人可以动态的加载无尽的模块,但是几乎所有的资源都是由几个基础模块开始分配的,所以添加对象跟踪相对比较简单.经过修改,运行,测试,从弱表中打印出来的数据发现,机器人中有大量的移动包和移动相关的计时器对象没有被gc掉,这些对象多数都已经存活了100秒以上.场景中NPC都是僵尸,每个移动的时间应该在5秒以下,所以可判定这些移动对象是泄漏.
问题的范围缩小了,但还是看不出哪段代码造成了泄漏?泄漏的对象在哪一个模块中被引用?
引用检索
定义:从某个节点开始搜索所有该节点引用的对象以及递归搜索子节点,找到要搜索的对象,打印出引用路径.
最常见的可以从_G开始搜索.搜索到的每个table,取其key和value递归搜索;搜索到的每个函数,取其upvalue递归搜索.至于是否需要搜索对象的环境表和metatable,以及全局registry表,则取决于具体需求.我因为用不上,就没有搜索这一部分.
搜索的时候注意标记已经搜索过的节点,避免重复搜索.最好能缩小搜索范围,而不是从_G开始搜索,另外应该能每次只搜索指定的部分引用而非全部,可以极大的缩短等待时间.搜索所有的引用其实相当耗时.
我定义的搜索接口是:function Search_r(obj, node, mark, result);
经过引用检索处理后,我看到了计时器模块引用了那些泄漏的移动包和移动计时器对象,这些对象的创建时间和引用他们的激活时间居然是相同的,这导致了这些计时器对象不会再激活,同时也失去了激活后释放的机会,造成了内存泄漏.而根本原因,则是移动处理模块在使用计时器的时候传入了0超时参数,因为僵尸走得太慢了.
到此,问题就算全部解决了.
posted on 2010-08-14 15:41
LOGOS 阅读(6955)
评论(2) 编辑 收藏 引用