随笔 - 119  文章 - 290  trackbacks - 0

博客搬家了哦,请移步
叫我abc

常用链接

留言簿(12)

随笔分类

我的博客

搜索

  •  

积分与排名

  • 积分 - 299130
  • 排名 - 84

最新评论

阅读排行榜

引子

最近用机器人做NPC的压力测试,突然发现一台机器能支持的机器人数量剧减,而且运行一段时间后整台机器直接内存耗光死机.经过观察,发现1个机器人在运行一段时间之后内存能占用到120M之多,而且还在不断增加,同时内存无法手动回收.
以前1个机器人大概消耗10M-20M的内存,这次的消耗明显异常了,所以初步判断逻辑上存在lua对象泄漏:在某些没有注意到的地方长期引用着不再使用的lua对象,导致这些对象无法被gc.
为了解决这个问题,google到一篇相似问题的文章,lua内存泄漏查证.文章的大概思路就是:

  1. 资源跟踪,定位哪些资源泄漏
  2. 引用检索,查找泄漏的资源被哪个模块引用

资源跟踪

定义:将应用中分配的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超时参数,因为僵尸走得太慢了.
到此,问题就算全部解决了.

PS:发现用html编辑blog非常不错啊,比cppblog自带的所见即所得编辑器好用多了,还可以用CSS和插入一些有趣的js.

posted on 2010-08-14 15:41 LOGOS 阅读(6846) 评论(2)  编辑 收藏 引用

FeedBack:
# re: 检测lua内存泄漏 2010-08-15 22:55 tp
有没有直接定位监测的啊?  回复  更多评论
  
# re: 检测lua内存泄漏 2010-08-16 12:00 LOGOS
@tp
也有办法
你可以通过遍历_G的方式记录各个资源的生存状况和引用路径  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理