nodejs内存泄露检测方法

发布者: xiaozhimn

memwatch-next 是memwatch(年久失修) 的一个 fork 分支,用来监测 Node.js 的内存泄漏和堆信息比较。以下简称 memwatch。下面我们以一段事件监听器导致的内存泄漏代码为例,讲解如何使用 memwatch。
Node.js 测试代码

let count = 1;
var memwatch = require('memwatch-next');
memwatch.on('stats', function(stats) {
    console.log(count++, stats);
});
memwatch.on('leak', function(info) {
    console.log("---");
    console.log(info);
    console.log("---");
});
var http = require("http");
var server = http.createServer(function(req, res) {
    for(var index = 0; index < 10000; index++) {
        server.on('request', function leakEventCallback() {});
    }
    res.end("hello world!");
    global.gc();
}).listen(3000);

运行该测试程序:

测试代码含义:每一个请求到来时,给 server 注册 10000 个 request 事件的回调函数(大量的事件回调函数存储到内存中,造成了内存泄漏),然后手动调用一次 gc。
注意: 这里添加 --expose-gc 参数启动,这样我们才可以在程序中主动调用 gc。

memwatch 可以监听两个事件:

stats:gc 事件,每执行一次 gc,触发该函数,打印 heap 相关信息。如下:
{
  num_full_gc: 1,// 完整的垃圾回收次数
  num_inc_gc: 1,// 增长的垃圾回收次数
  heap_compactions: 1,// 内存压缩次数
  usage_trend: 0,// 使用趋势
  estimated_base: 5350136,// 预期基数
  current_base: 5350136,// 当前基数
  min: 0,// 最小值
  max: 0// 最大值
}
leak:内存泄露事件,触发该事件的条件是:连续 5  gc 后内存都是增长的。打印如下:
{
  growth: 4051464,
  reason: 'heap growth over 5 consecutive GCs (2s) - -2147483648 bytes/hr'
}
运行:

$ ab -n 10 -c 1 http://localhost:3000/
结果:

(node) warning: possible EventEmitter memory leak detected. 11 request listeners added. Use emitter.setMaxListeners() to increase limit.
Trace
    at Server.addListener (events.js:239:17)
    at Server. (/Users/nswbmw/Desktop/test/app.js:17:12)
    at emitTwo (events.js:87:13)
    at Server.emit (events.js:172:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:536:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:103:23)
1 { num_full_gc: 1,
  num_inc_gc: 1,
  heap_compactions: 1,
  usage_trend: 0,
  estimated_base: 5350640,
  current_base: 5350640,
  min: 0,
  max: 0 }
2 { num_full_gc: 2,
  num_inc_gc: 2,
  heap_compactions: 2,
  usage_trend: 0,
  estimated_base: 6836048,
  current_base: 6836048,
  min: 0,
  max: 0 }
3 { num_full_gc: 3,
  num_inc_gc: 4,
  heap_compactions: 3,
  usage_trend: 0,
  estimated_base: 7763064,
  current_base: 7763064,
  min: 7763064,
  max: 7763064 }
4 { num_full_gc: 4,
  num_inc_gc: 6,
  heap_compactions: 4,
  usage_trend: 0,
  estimated_base: 8347624,
  current_base: 8347624,
  min: 7763064,
  max: 8347624 }
---
{ growth: 3775840,
  reason: 'heap growth over 5 consecutive GCs (0s) - -2147483648 bytes/hr' }
---
......
可以看到:Node.js 已经警告我们事件监听器超过了 11 个,可能造成内存泄露。触发的 leak 事件打印出增长了多少内存(bytes)和原因及预估每小时增长多少 bytes。只告诉我们内存泄漏貌似没啥用,下面我们看个有用点的功能。
0赞