浅析Node.js中的内存泄漏问题(2)

node-memwatch能够在任何一个JS对象分配之前,紧随着一次完整的垃圾回收和内存压缩发出一个内存使用样本。(它使用了V8的post-gc钩子,V8::AddGCEpilogueCallback,来在每次垃圾回收触发时收集堆使用信息)

统计数据包括:

    usage_trend(使用趋势)

    current_base(当前基数)

    estimated_base(预期基数)

    num_full_gc (完整的垃圾回收次数)

    num_inc_gc (增长的垃圾回收次数)

    heap_compactions (内存压缩次数)

    min (最小)

    max (最大)

这里有一个展示存在内存泄露的应用的数据看起来是什么样的例子。下面的图表随着时间追踪内存的使用。疯狂的绿线展示了process.memoryUsage()报告的内容。红线展示了node_memwatch报告的current_base。左下侧的盒子展示了附加信息。

2015623152204606.png (572×441)

注意Incr GCs非常高。那说明V8在拼命的尝试清理内存。

memwatch.on('leak', ...): 堆分配趋势

我们定义了一个简单的侦测算法来提醒你应用程序可能存在内存泄漏。即如果经过连续五次GC,内存仍被持续分配而没有得到释放,node-memwatch就会发出一个leak事件。事件的具体信息格式是明了易读的,就像这样:
 

{ start: Fri, 29 Jun 2012 14:12:13 GMT, end: Fri, 29 Jun 2012 14:12:33 GMT, growth: 67984, reason: 'heap growth over 5 consecutive GCs (20s) - 11.67 mb/hr' }

memwatch.HeapDiff(): 查找泄漏元凶

最后,node-memwatch能比较堆上对象的名称和分配数量的快照,其对比前后的差异可以帮助找出导致内存泄漏的元凶。
 

var hd = new memwatch.HeapDiff(); // Your code here ... var diff = hd.end();

对比产生的内容就像这样:
 

{ "before": { "nodes": 11625, "size_bytes": 1869904, "size": "1.78 mb" }, "after": { "nodes": 21435, "size_bytes": 2119136, "size": "2.02 mb" }, "change": { "size_bytes": 249232, "size": "243.39 kb", "freed_nodes": 197, "allocated_nodes": 10007, "details": [ { "what": "Array", "size_bytes": 66688, "size": "65.13 kb", "+": 4, "-": 78 }, { "what": "Code", "size_bytes": -55296, "size": "-54 kb", "+": 1, "-": 57 }, { "what": "LeakingClass", "size_bytes": 239952, "size": "234.33 kb", "+": 9998, "-": 0 }, { "what": "String", "size_bytes": -2120, "size": "-2.07 kb", "+": 3, "-": 62 } ] } }

HeapDiff方法在进行数据采样前会先进行一次完整的垃圾回收,以使得到的数据不会充满太多无用的信息。memwatch的事件处理会忽略掉由HeapDiff触发的垃圾回收事件,所以在stats事件的监听回调函数中你可以安全地调用HeapDiff方法。

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgdjsp.html