node扩展 memwatch分析
发布网友
发布时间:2024-10-12 04:58
我来回答
共1个回答
热心网友
时间:2024-11-07 23:31
memwatch是一个C++扩展,主要用于检测Node.js中的内存泄漏问题。它的基本用法包括配置文件binding.gyp,以及src目录下的多个源文件如heapdiff.cc、init.cc、memwatch.cc、util.cc。这些文件通过node模块系统在编译过程中找到依赖的nan目录。memwatch的入口函数在init.cc文件中,通过`NODE_MODULE(memwatch, init);`声明。当执行`require('@airbnb/memwatch')`时,首先调用init函数,此函数接收`v8:Handle target`作为参数,类比于Node.js的`mole.exports`的`exports`对象。函数内部主要分为三部分:初始化`target`、绑定`upon_gc`和`gc`两个函数,并在Node.js的`gc`前后分别挂上对应的钩子函数。
在`heapdiff.cc`文件中,`heapdiff::HeapDiff::Initialize(target);`的实现创建了一个名为HeapDiff的函数`t`,同时在`t`的原型链上绑定了`end`方法,使得JS层面可以执行`var hp = new memwatch.HeapDiff(); hp.end()`。
当JS执行`new memwatch.HeapDiff();`时,C++层面调用`heapdiff::HeapDiff::New`函数,其精简版如下:用户在JS层面执行`var hp = new memwatch.HeapDiff();`时,C++层面通过Node.js的API对堆上内存打一个快照保存到`self->before`中,并将当前对象返回出去。
`memwatch.HeapDiff.End`实现当用户执行`hp.end()`时,会执行原型链上的`end`方法,即C++的`heapdiff::HeapDiff::End`方法。其简化版如下:拿到当前的HeapDiff对象后,再对当前堆上内存打一个快照,通过`compare`函数对比前后两个快照后得到`comparison`,然后将快照释放,并将结果通知给JS。
`compare`函数内部会递归调用`buildIDSet`函数得到堆快照的差结果。`buildIDSet`函数构造了两个对象`b(before)`、`a(after)`用于保存前后两个快照的详细信息。在实现中,构造了JS对象描述如下:进一步对前后两次的快照进行分析可以得到`o`,`o`中的`before`、`after`对象就是前后两次的快照引用。
`buildIDSet`、`setDiff`以及`manageChange`函数实现分别用于:从堆快照的根节点出发,递归寻找所有可达节点,做DFS统计所有可达节点的同时,也统计当前堆占用的内存大小;计算集合差集;做数据聚合。这些函数具体实现不在赘述。
`upon_gc`和`gc`方法在`init`函数中声明。`gc`方法实际上对应`memwatch::trigger_gc`,通过`Nan::IdleNotification`和`Nan::LowMemoryNotification`触发V8的GC功能。`upon_gc`方法绑定了一个函数,当执行到`gc`方法时,就会触发该函数,其中`info[0]`是用户传入的回调函数。
`memwatch::before_gc`和`memwatch::after_gc`方法实现,前者开始记录时间,后者在GC后记录结果到`GCStats`结构体中。将结果保存到`barton`中,通过`libuv`的`loop`触发回调函数,用户可以获取到GC的统计结果,并通过回调函数处理。