节点JS应用程序内存压力上升

我正在研究一个Node JS应用程序,并面临严重的内存压力问题。 以下是启动应用程序(恒定负载)60分钟内的内存使用趋势:

在这里输入图像说明

记忆用途大幅上涨至95%,但之后保持相当稳定。

我之前和之后采取了内存转储,但似乎有一些与我如何捕获转储的问题,因为两个转储文件之间的差异只是几个MB。

这是在chrome分析中heapdump的样子:

在这里输入图像说明

但是我对这个很陌生,不确定我应该找什么。

有人可以提供任何关于如何找出内存问题的指针,如何检测内存泄漏,或如何理解这里提到的heapdump文件?

节点版本:0.12.14

输出为 – find node_modules -type f -name "*.node" – 如下所示:

 node_modules/simpleflake/node_modules/bignum/build/Release/bignum.node node_modules/simpleflake/node_modules/bignum/build/Release/obj.target/bignum.node node_modules/heapdump/build/Release/addon.node node_modules/heapdump/build/Release/obj.target/addon.node node_modules/couchbase/build/Release/couchbase_impl.node 

npm list --depth=0输出如下:

 aws-sdk@2.5.3 body-parser@1.11.0 check-types@6.0.0 couchbase@2.2.2 elasticsearch@10.1.3 expect@1.20.2 express@4.14.0 jshint@2.9.3 minimist@1.1.3 mocha@2.5.3 moment@2.9.0 morgan@1.5.3 newrelic@1.30.0 request@2.53.0 simpleflake@1.0.0 underscore@1.7.0 why-is-node-running@1.2.2 (https://github.com/mindtickle/why-is-node-running.git#96f3c8da54b110e8a9a1423361d2da7c125784f6) winston@1.0.2 winston-aws-cloudwatch@0.4.2 

另外,是否有可能看到我正在使用的任何包是否负责内存泄漏?

提前致谢。

要看的两个主要领域是对象保留和原生泄漏。 对于在虚拟机上运行的大多数垃圾收集语言来说,这也是一样

最有可能的是,你的应用程序或模块中有一些东西保留对象的引用并填充对象空间。

接下来是使用本机代码和泄漏本地内存的模块,这些内存不会显示在GC对象空间中。

然后Node.js本身可能有一个本地泄漏,这是不可能的,因为有大量的用户,但它总是一个可能性,尤其是与旧版本的Node.js。

应用程序内存和垃圾收集

运行您的应用程序,打开节点垃圾收集日志logging

 node --trace_gc --trace_gc_verbose app.js 

这将提供每个GC事件的信息块。 主要的信息是第一行,告诉你Node.js以前使用了多less内存,在GC之后。

 [97577:0x101804a00] 38841 ms: Scavenge 369.0 (412.2) -> 356.0 (414.2) MB, 5.4 / 0 ms [allocation failure]. 

--trace_gc_verbose为您提供所有的行,每个内存空间都有更多的细节。

 [97577:0x101804a00] Memory allocator, used: 424180 KB, available: 1074956 KB [97577:0x101804a00] New space, used: 789 KB, available: 15334 KB, committed: 32248 KB [97577:0x101804a00] Old space, used: 311482 KB, available: 0 KB, committed: 321328 KB [97577:0x101804a00] Code space, used: 22697 KB, available: 3117 KB, committed: 26170 KB [97577:0x101804a00] Map space, used: 15031 KB, available: 3273 KB, committed: 19209 KB [97577:0x101804a00] Large object space, used: 14497 KB, available: 1073915 KB, committed: 14640 KB [97577:0x101804a00] All spaces, used: 364498 KB, available: 1095640 KB, committed: 413596 KB [97577:0x101804a00] External memory reported: 19448 KB [97577:0x101804a00] Total time spent in GC : 944.0 ms 

绘制这些值通常看起来像锯齿。 这种“锯齿”发生在多个层次上,随着不同的内存空间填满,达到极限,然后被垃圾收集回来。 来自Dynatraces About Performance的博客文章在Node.js中了解垃圾收集和狩猎内存泄漏显示了一个缓慢增加对象空间的应用程序 看起来像锯齿

随着时间的推移,你应该看到哪些内存区域正在增长,哪些没有,并且可以为你提供一些上下文,了解代码保持对象引用的情况 如果你没有在堆中看到任何内存增长,你可能会有一个真正的内存泄漏,无论是在本地模块或Node.js本身。

进程内存

垃圾收集器使用的node应用程序正在报告的内存(称为“堆”)并不总是与操作系统正在报告的进程相匹配。 操作系统可以有更多的内存分配Node.js目前可能不会使用。 这可能是正常的,如果操作系统没有受到内存压力,并且Node.js垃圾收集对象,那么操作系统会为进程保留额外的内存空间。 当某些东西在泄漏并且分配的过程内存不断增长时,这也可能是exception的。

与您的应用程序一起收集一些操作系统内存信息

 node --trace_gc app.js & pid=$! while sleep 15; do pss=$(sudo awk '/^Pss/{p=p+$2}END{print p}' /proc/$pid/smaps) echo "$(date) pss[$pss]" done 

这将给你一个date和内存的值与你的GC输出的字节进行比较:

 [531:0x101804a00] 12539 ms: Scavenge 261.6 (306.4) -> 246.6 (307.4) MB, 5.0 / 0 ms [allocation failure]. Tue Aug 30 12:34:46 UTC 2016 pss[3396192] 

smapsPss数字考虑到了共享内存的重复,所以比ps使用的Rss数字更精确

Heapdumps

如果您发现垃圾收集日志内存匹配操作系统进程内存增长,那么很可能应用程序或它依赖的模块将保留对旧对象的引用,您将需要开始查看堆转储以确定这些对象是什么。

使用node-inspector并以debugging模式运行您的应用程序,以便您可以附加到它并创build一个堆转储。

 npm install -g node-inspector node-inspector & node --debug app.js 

就像应用程序启动一样,把头转储。 在记忆增长的中间某个地方。 然后接近最大的时候(碰撞之前!)。

比较3个堆转储在后两个转储中查找大对象或严重重复的对象引用。

本机泄漏

如果GC日志没有显示内存的增加,但是操作系统为节点进程执行操作,则可能是本机泄漏。

OSX有一个有用的开发工具叫做leaks ,可以在没有完全debugging的情况下find进程中未被引用的内存。 我相信valgrind可以用--leak-check=yes做同样的事情。

这些可能不能确定是什么错,只是确认问题是本地泄漏。

模块

要在您的应用程序中查找本地模块,请使用以下命令:

 find node_modules -type f -name "*.node" 

对于这些模块中的每一个,都会生成一个小的testing用例,说明每个模块在应用程序中的使用情况,并在检查泄漏时对其进行压力testing。

您也可以尝试从应用程序中暂时排除或禁用任何本机模块,以排除或突出显示这些模块的原因

Node.js的

如果可能,请尝试使用不同版本的Node.js。 移动到最新的主要版本,最新的次要/补丁,或回到主要版本,看看是否改善或改变内存configuration文件。

v4.x或v6.x版本的v6.x版本中的通用内存pipe理有很大的改进。 如果可以更新,问题可能会通过错误修复或V8更新消失。