[交流帖] 如何调试内存泄露
发布于 9 年前 作者 crystaldust 4677 次浏览 最后一次编辑是 8 年前 来自 问答

如题,因为npmjs上的第三方库良莠不齐,时不时会遇到各种问题,以我自己的经历为例。产品1月底上线,我现在都要从公司离职了,直到昨天才把内存泄露彻底排查清楚。回想最初发布的时候server莫名其妙crash,一直到排查清楚,那无数个担惊受怕的周末和夜晚,顿感心有余悸啊。

扯淡完毕,接下来分享一下我的土办法,抛砖引玉,欢迎大家分享更好的调试方法。我是这么干的: 测试server端 node-dev + memwatch,每次内存回收时观察内存使用情况,然后从另一台机器写一个脚本不断发送请求(所有API都cover),然后检查server端的输出情况。定位到有泄漏的API后,进去一点点排查,方法就是(太土了,简直不好意思说)提前return callback,就跟查哪段电线短路似的,我在这设一下,没有泄露,再往后一点段设置一下,有泄漏,就说明这之间的代码有问题,最终定位到有泄漏代码。

发现的泄漏都是出于第三方模块:

  • ZeroRPC,前dotCloud公司(没错,就是现在红遍全球的Docker公司的前身)开发的基于ZeroMQ的远程调用框架,后来没人维护了,npm上的版本有严重的内存漏洞。后来去github上提,没回复,最后直接给作者发邮件问了,然后说作者说问一下Docker的人。然后就没消息了。直到发帖前又查了一下,发现最近这个项目又重新有人维护了,4天前迁移到了新的github项目。内存泄露的具体原因可以参考issue https://github.com/0rpc/zerorpc-node/issues/57#event-323473247

  • Mongoose,3.x的版本,具体记不清排查的时候是哪些版本了,执行find,findOne的时候,如果文档是个比较大的对象,会导致内存泄露。所以执行查询的时候最好指定必须的字段,这样查询速度更快。另外发现直接用collection查询更快一些,例如有一个collection的model定义为Book:

// The code is faster than Book.find(...)
Book.collection.find( { published_date : { $gt : new Date( 2015, 0, 1 ) } } )

所以如果仅仅是查询,又不需要用到Mongoose封装的一些高级功能,可以直接用collection查询

  • underscore 某些版本的underscore在执行大量的each时,会导致轻微的内存增加,不算泄露吧,但是比直接for循环要使用更多的内存。
3 回复

好吧,如果是get请求内存泄露,可能能用你的办法,如果是添加数据的时候内存泄露呢。。。。。 而且如果是线上环境才有,测试环境测不出来。。。 memwatch的帮助实在有限,不能帮助缩小问题查找范围。

Mongoose的话,4.0.2应该是有比较明显的内存泄露,更新的版本不知道了。

@chita 能具体说一下添加数据的时候内存泄露是怎么个情况嘛?另外为什么线上环境和测试环境会不一样呢?很感兴趣

关注下 自豪地采用 CNodeJS ionic

回到顶部