Node.js V8内存GC分配失败。

16

我正在尝试使用一个“什么也不做”的服务器来分析nodejs v8的内存。 我使用了node-memwatch来获取堆差异信息。 我在连接之前和连接关闭后收集了堆信息。 我尝试了来自客户端的200个并发连接。

这是连接关闭后的垃圾回收跟踪。

有人能帮我理解:

1.为什么内存会增加? 在连接关闭后,服务器绝对什么也没做。 它不应该随着垃圾被收集而始终下降吗?
2.那些分配失败是什么? 我该如何真正解释这里的跟踪?

 15802 ms: Mark-sweep 8.9 (45.0) -> 8.1 (45.0) MB, 58 ms [allocation failure] [GC in old space forced by flags].
 16144 ms: Mark-sweep 9.2 (45.0) -> 8.4 (45.0) MB, 53 ms [allocation failure] [GC in old space forced by flags].
 16495 ms: Mark-sweep 9.5 (45.0) -> 8.7 (46.0) MB, 60 ms [allocation failure] [GC in old space forced by flags].
 16837 ms: Mark-sweep 9.8 (46.0) -> 9.0 (46.0) MB, 56 ms [allocation failure] [GC in old space forced by flags].
 17197 ms: Mark-sweep 10.1 (46.0) -> 9.4 (46.0) MB, 62 ms [allocation failure] [GC in old space forced by flags].
 17905 ms: Mark-sweep 11.5 (46.0) -> 10.0 (47.0) MB, 74 ms [Runtime::PerformGC] [GC in old space forced by flags].                                                               
 18596 ms: Mark-sweep 12.2 (47.0) -> 10.7 (47.0) MB, 75 ms [Runtime::PerformGC] [GC in old space forced by flags].
 19315 ms: Mark-sweep 12.8 (47.0) -> 11.3 (48.0) MB, 83 ms [allocation failure] [GC in old space forced by flags].
 20035 ms: Mark-sweep 13.4 (48.0) -> 12.0 (49.0) MB, 90 ms [Runtime::PerformGC] [GC in old space forced by flags].
 21487 ms: Mark-sweep 16.0 (49.0) -> 13.2 (50.0) MB, 96 ms [Runtime::PerformGC] [GC in old space forced by flags].
 22950 ms: Mark-sweep 17.3 (50.0) -> 14.5 (52.0) MB, 116 ms [Runtime::PerformGC] [GC in old space forced by flags].
 24376 ms: Mark-sweep 18.8 (52.0) -> 15.9 (53.0) MB, 114 ms [allocation failure] [GC in old space forced by flags].
 25849 ms: Mark-sweep 19.9 (53.0) -> 17.2 (54.0) MB, 129 ms [Runtime::PerformGC] [GC in old space forced by flags].
 28773 ms: Mark-sweep 25.2 (54.0) -> 19.7 (57.0) MB, 149 ms [allocation failure] [GC in old space forced by flags].
 31725 ms: Mark-sweep 27.7 (57.0) -> 22.2 (59.0) MB, 172 ms [Runtime::PerformGC] [GC in old space forced by flags].
 34678 ms: Mark-sweep 30.2 (59.0) -> 24.7 (61.0) MB, 190 ms [Runtime::PerformGC] [GC in old space forced by flags].
 44045 ms: Mark-sweep 28.4 (61.0) -> 25.8 (63.0) MB, 180 ms [idle notification] [GC in old space forced by flags].
 44216 ms: Mark-sweep 25.8 (63.0) -> 25.8 (63.0) MB, 170 ms [idle notification] [GC in old space requested].
 57471 ms: Mark-sweep 26.9 (63.0) -> 25.8 (62.0) MB, 167 ms [Runtime::PerformGC] [GC in old space forced by flags].
 57651 ms: Mark-sweep 26.8 (62.0) -> 25.5 (62.0) MB, 160 ms [Runtime::PerformGC] [GC in old space forced by flags].
 57828 ms: Mark-sweep 26.5 (62.0) -> 25.5 (62.0) MB, 159 ms [Runtime::PerformGC] [GC in old space forced by flags].

谢谢,

2个回答

8
"分配失败"听起来非常戏剧化,但实际上没有真正的失败。它只是意味着我们分配了太多的内存,因此该进行垃圾回收来查看是否可以收集一些内存。
看起来你正在使用--gc-global标志(“通过标志强制进行GC”)。这对于生产来说是一个不好的选择,尽管在调试时缩小问题范围可能没问题。
我无法确定为什么您的进程会泄漏。您可能会发现堆分析器很有用。请参见https://github.com/felixge/node-memory-leak-tutorial

是的,我正在使用--gc-global和compact来确保在进行堆差分之前收集所有垃圾。这只是小问题。问题是为什么在垃圾回收期间内存会增加? - haijin

2

根据代码:

PrintF("%s %.1f (%.1f) -> %.1f (%.1f) MB, ",
       CollectorString(),
       static_cast<double>(start_object_size_) / MB,                                                                                    
       static_cast<double>(start_memory_size_) / MB, 
       SizeOfHeapObjects(),
       end_memory_size_mb);

每一行都代表一个垃圾回收(gc)过程,当gc开始时,
start_object_size_ = heap_->SizeOfObjects();

在垃圾回收总结中:
PrintF("total_size_before=%" V8_PTR_PREFIX "d ", start_object_size_);                                                                   
PrintF("total_size_after=%" V8_PTR_PREFIX "d ", heap_->SizeOfObjects());

关于为什么在我的应用程序空闲时,start_object_size_会增加,我猜测可能是在垃圾回收期间,一些对象被提升到老年代,导致老年代中的对象大小增加。


即使这些年过去了,这对我仍然很有用,因为它给了我在代码中搜索的线索。以下是当前的代码:https://github.com/nodejs/node/blob/baa9e652142d0fa02ef21f561ddcdfda6372305f/deps/v8/src/heap/gc-tracer.cc#L535 - bmacnaughton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接