IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

一个 Lua 内存泄露检查工具

云风的 BLOG 2012-12-13 13:33:54 累计浏览 4,008 次
本机暂存

   昨天我们发现每日构建的服务器突然在一个晚上内存暴增了 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. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. Nginx与Lua (累计阅读 5,670)
  2. 了解前端内存泄露 (累计阅读 5,596)
  3. Lua GC 的源码剖析 (2) (累计阅读 5,077)
  4. Ameba , 一个简单的 lua 多线程实现 (累计阅读 4,981)
  5. Lua GC 的源码剖析 (4) (累计阅读 4,775)
  6. Proto Buffers in Lua (累计阅读 4,402)
  7. Lua GC 的源码剖析 (1) (累计阅读 4,390)
  8. Lua GC 的源码剖析 (6) 完结 (累计阅读 3,926)
  9. 回调还是消息队列 (累计阅读 3,896)
  10. RedBridge(redis的http接口) (累计阅读 3,860)