一个 Lua 内存泄露检查工具
昨天我们发现每日构建的服务器突然在一个晚上内存暴增了 8 G ,显然是发生了内存泄露。
之前,我们在 skynet 里留下了许多调试协议,使我们很快的确定了发生泄露的服务:在一张地图的 lua State 中。可以确定是地图的 lua 实现中,有些 lua 对象在不断的生成。生成速度不快,但确实没有人解开引用,导致内存持续增长。
曾经有很多人做过 Lua 的内存分析工具,但是我懒的去搜了,花了半天时间自己写了一个。(已经开源在 github 上)
原理是这样的:
这个叫作 snapshot 的库,只提供一个函数,它可以对当前的 Lua State 做一个完整的快照。但由于我并不像做 Lua State 的序列化工作(虽然做法很像),为了减少分析数据,只记录了复杂对象的引用关系。
即,记录下所有 table thread userdata function 间的引用。
我们可以在不同时间,对 Lua State 拍两个快照,相比较后,就很容易知道新增加的内存处于何处了。
一开始我想用 lua 来编写这个工具,其实也的确做的到。但如果有 Lua 写就得相当小心,因为 Lua 代码的运行过程本身会影响 State ,即,你想对它观察,就可能改变它。
用 C 直接调用 lua API 来遍历 lua State ,影响要小的多。
最终得到的对象引用关系数据其实很丰富,但因为我希望结果对 State 的影响小一些,就把一些信息合并成字符串储存到结果表内了。 snapshot 的返回结果只是一张简单的 table ,每个 Lua 对象,都以指针(lightuserdata) 为 key 储存在表中;对应的 value 是一个 string 足够详细的描述了这个对象的引用关系。
比如例子中的 dump.lua 这段程序,运行后就会得到这样的结果:
userdata: 0052E760 table 00521810 : tmp : dump.lua:7 userdata: 0052EB98 table 00521810 : S1 : dump.lua:7
这表示,两次 snapshot 间,增加了两个 table 。它们是被运行在源代码 dump.lua:7 处的函数中 tmp 和 S1 两个变量引用住了。
snapshot 生成的报告不太利于人阅读,但你可以写代码做进一步分析。比如可以逐级建立 table 的引用关系,用更人性的方式展现出来。由于只是一个临时工具,它也已经快速的帮我们定位了昨天的内存泄露问题所在,暂时我就不花精力去完善它了。
建议继续学习:
- 近期Imgsrc一处内存泄露问题的查找和解决 (阅读:5558)
- Nginx与Lua (阅读:4762)
- 了解前端内存泄露 (阅读:4577)
- GLIBC内存分配机制引发的“内存泄露” (阅读:4021)
- Lua GC 的源码剖析 (2) (阅读:3967)
- Ameba , 一个简单的 lua 多线程实现 (阅读:3659)
- GC与JS内存泄露 (阅读:3530)
- Lua GC 的源码剖析 (4) (阅读:3503)
- 使用 luajit 的 ffi 绑定 zeromq (阅读:3420)
- Proto Buffers in Lua (阅读:3205)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:云风的 BLOG 来源: 云风的 BLOG
- 标签: Lua 内存泄露
- 发布时间:2012-12-13 13:33:54
- [69] Twitter/微博客的学习摘要
- [64] find命令的一点注意事项
- [64] 如何拿下简短的域名
- [64] IOS安全–浅谈关于IOS加固的几种方法
- [63] android 开发入门
- [62] Go Reflect 性能
- [61] 流程管理与用户研究
- [59] Oracle MTS模式下 进程地址与会话信
- [58] 读书笔记-壹百度:百度十年千倍的29条法则
- [58] 图书馆的世界纪录