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

时间:2016-08-30 08:51:49

标签: node.js memory memory-leaks node-heapdump

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

enter image description here

记忆用法急剧上升到95%,但之后保持相当稳定。

我之前和之后都进行了内存转储,但似乎有一些问题我如何捕获转储,因为两个转储文件之间的区别只有几MB。

这是chromedump在chrome profiling中的样子:

enter image description here

但我对此很陌生,不确定我应该寻找什么。

有人可以提供有关如何找出内存问题,如何检测内存泄漏或如何理解这里提到的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

此外,是否可以查看我使用的任何软件包是否导致内存泄漏?

提前致谢。

1 个答案:

答案 0 :(得分:4)

要考虑的两个主要方面是对象保留和本机泄漏。这适用于在VM上运行的大多数垃圾收集语言

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

接下来是使用本机代码和泄漏本机内存的模块,它们不会出现在GC对象空间中。

然后Node.js本身可能有本机泄漏,由于用户数量很多,这种情况不太可能,但它总是有可能,特别是对于旧版本的Node.js.

应用程序内存和垃圾收集

运行启用了节点垃圾收集日志记录的应用程序

node --trace_gc --trace_gc_verbose app.js

这将提供有关每个GC事件的信息块。主要信息是第一行,它告诉您之前Node.js使用了多少内存,并且在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 blog Understanding Garbage Collection and hunting Memory Leaks in Node.js帖子的此图表显示应用程序缓慢增加其对象空间looks like a sawtooth

随着时间的推移,您应该看到哪些内存区域增长,哪些内存区域不会增加,哪些内容可以为您提供保留对象引用的代码的上下文。如果您没有在堆中看到任何内存增长,则可能在本机模块或Node.js本身中存在真正的内存泄漏。

进程内存

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

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

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

这将为您提供与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]

Pss中的smaps数字考虑了共享内存重复,因此比Rss

使用的ps数字更准确

Heapdumps

如果确实找到了与操作系统进程内存增长相匹配的垃圾收集日志内存,那么它很可能是应用程序,或者它所依赖的模块是保留对旧对象的引用,您需要开始查看堆转储识别那些对象是什么。

使用node-inspector并在调试模式下运行您的应用,以便您可以附加到它并创建堆转储。

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

在应用程序启动时进行头部转储。在内存增长的中间某处。然后接近最大值(崩溃之前!)。

比较3个堆转储,在后两个转储中查找大对象或重复对象引用,与第一个转储相比。


原生泄漏

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

OSX有一个名为leaks的有用开发工具,可以在没有完全调试的情况下在进程中找到未引用的内存。我相信valgrind可以使用--leak-check=yes执行相同类型的操作。

这些可能无法识别出错误,只是确认问题是原生泄漏。

模块

要在应用中查找本机模块,请使用以下命令:

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

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

您还可以尝试暂时排除或禁用应用程序中的任何本机模块以将其排除或将其突出显示为原因

Node.js的

如果可能,请尝试使用不同版本的Node.js.移至最新的主要版本,最新的次要/补丁或返回主要版本,以查看内存配置文件是否有任何改进或更改。

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