技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> 系统运维 --> 一个 Lua 内存泄露检查工具

一个 Lua 内存泄露检查工具

浏览:3096次  出处信息

   昨天我们发现每日构建的服务器突然在一个晚上内存暴增了 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 的引用关系,用更人性的方式展现出来。由于只是一个临时工具,它也已经快速的帮我们定位了昨天的内存泄露问题所在,暂时我就不花精力去完善它了。

建议继续学习:

  1. 近期Imgsrc一处内存泄露问题的查找和解决    (阅读:5558)
  2. Nginx与Lua    (阅读:4762)
  3. 了解前端内存泄露    (阅读:4577)
  4. GLIBC内存分配机制引发的“内存泄露”    (阅读:4021)
  5. Lua GC 的源码剖析 (2)    (阅读:3967)
  6. Ameba , 一个简单的 lua 多线程实现    (阅读:3659)
  7. GC与JS内存泄露    (阅读:3530)
  8. Lua GC 的源码剖析 (4)    (阅读:3503)
  9. 使用 luajit 的 ffi 绑定 zeromq    (阅读:3420)
  10. Proto Buffers in Lua    (阅读:3205)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1