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。左下侧的盒子展示了附加信息。
注意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方法。
在下图中,我们加上了堆内存对象分配数量排行:
下一步怎么做
node-memwatch提供了:
准确的内存使用情况跟踪
疑似内存泄漏通知
堆差异比较
这是跨平台的
并且不要求任何额外的设备
我们想要它的功能更多。特别是,我们希望node-memwatch能够提供一些导致内存泄漏的对象的使用案例(例如,变量名称,数组下标或闭包代码)。
我们希望您能在调试Node应用程序泄漏问题时发现memwatch很好用,也希望您能复制一份代码并帮助我们做得更好。
下面的内容你可能也喜欢: