节点进程内存不足

时间:2016-06-22 18:44:18

标签: node.js stack out-of-memory

我想理解为什么简单的节点进程耗尽内存。

出于乐趣,我尝试console.log 1000万次,一段时间后我出错了

<--- Last few GCs --->

  215529 ms: Scavenge 1485.5 (1532.7) -> 1485.5 (1532.7) MB, 43.9 / 0 ms (+ 1.8 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep].
  216476 ms: Mark-sweep 1485.5 (1532.7) -> 1435.3 (1482.5) MB, 947.9 / 0 ms (+ 2.9 ms in 2 steps since start of marking, biggest step 1.8 ms) [last resort gc].
  217537 ms: Mark-sweep 1435.3 (1482.5) -> 1435.3 (1482.5) MB, 1060.2 / 0 ms [last resort gc].


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x76575fe3ac1 <JS Object>
    1: _writeGeneric [net.js:645] [pc=0x1f0bf7164345] (this=0x6175737bfe9 <a WriteStream with map 0x3dda56221639>,writev=0x76575f04299 <false>,data=0x3d61a01691b9 <String[18]\: madan chutiya hai\n>,encoding=0x76575fed8d9 <String[4]: utf8>,cb=0x61757359889 <JS Function WritableState.onwrite (SharedFunctionInfo 0x61757359411)>)
    2: writeOrBuffer(aka writeOrBuffer) [_stream_writable.js:~255] [pc...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Abort trap: 6

我正在执行的简单程序是

for (var index = 0; index < 10000000; index++) {
        console.log('hello world');
}

内存不足错误的原因是什么?

2 个答案:

答案 0 :(得分:3)

<强>更新

Ben Noordhuis在这里谈论console.log内存:https://groups.google.com/forum/#!topic/nodejs/KtONbpVV68U

&#34;每个console.log()语句分配一些不是的内存 回收到事件循环的下一个滴答。&#34;

这就是为什么你的内存不足,即使你不一定要创建一堆对象。

<强>原始

基于@Vasil的评论,我认为他是对的。事件循环被阻止,无法运行垃圾回收。 FWIW我在节点v6.2.2上运行示例代码时没有遇到任何问题。但如果您使用已分配的内存,我可以通过添加以下标志来重现您的问题:--max-executable-size=192 --max-old-space-size=256 --max-semi-space-size=2。为了证明process.nextTick()理论,我们可以将您的测试脚本修改为:

// test.js
var BATCH_LIMIT = 250000;
var TEN_MILLION = 10000000;

var useNextTick = true; // switch to false to reproduce out of memory error

function log(start, end) {
  for(var index = start || 0; index<end; index++) {
    console.log('hello world', index);
    // if useNextTick is enabled we will call next tick every 250,000 iterations so GC can run
    if(useNextTick && index && index % BATCH_LIMIT === 0) {
      console.log('NEXT TICK');
      // bind the next start and end points to the log function that process.nextTick will call
      return process.nextTick(log.bind(this, index+1, index + (TEN_MILLION - index)));
    }
  }
}

// kick it off with 10,000,000 iterations
log(0, TEN_MILLION);

用有限的记忆运行它:

node --max-executable-size=192 --max-old-space-size=256 --max-semi-space-size=2 test.js

可能有一种更清晰的编码方式,但希望它可以让您了解实际发生的事情以及为什么重要的是不阻止事件循环。

答案 1 :(得分:2)

你也可以像这样使用--expose-gc Node.js标志:

https://simonmcmanus.wordpress.com/2013/01/03/forcing-garbage-collection-with-node-js-and-v8/

然后使用

global.gc();
循环内的

;尝试与process.nextTick()

结合使用