在nodejs中的console.log循环
我的MCVE是以下
var i = 0; for(;;) console.log(i++)
当我这样做,在某个特定的时刻,我的nodejs
只是停止打印东西,给我一个看起来像这样的输出
[...] 684665 684666 684667
然后,我得到这个:
<--- Last few GCs ---> 69097 ms: Scavenge 1397.2 (1456.7) -> 1397.2 (1456.7) MB, 0.8 / 0 ms (+ 1.7 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep]. 70462 ms: Mark-sweep 1397.2 (1456.7) -> 1396.0 (1456.7) MB, 1364.9 / 0 ms (+ 2.8 ms in 2 steps since start of marking, biggest step 1.7 ms) [last resort gc]. 71833 ms: Mark-sweep 1396.0 (1456.7) -> 1397.1 (1456.7) MB, 1370.2 / 0 ms [last resort gc]. <--- JS stacktrace ---> ==== JS stack trace ========================================= Security context: 0xcdf79d37399 <JS Object> 1: formatPrimitive(aka formatPrimitive) [util.js:~411] [pc=0x634d9f4113f] (this=0xcdf79d04131 <undefined>,ctx=0x17b18f4d561 <an Object with map 0x32fd25043ef9>,value=16248021) 2: formatValue(aka formatValue) [util.js:223] [pc=0x634d9f1fdbb] (this=0xcdf79d04131 <undefined>,ctx=0x17b18f4d561 <an Object with map 0x32fd25043ef9>,value=16248021,recurseTimes=2) 3: inspect(aka inspect) [uti... FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory [1] 19446 abort (core dumped) node
我想知道,什么console.log
可以导致内存不足的错误?
根据这个讨论: https : //groups.google.com/forum/#!topic/ nodejs/ KtONbpVV68U
每次调用console.log
(或其他日志logging方法)时,控制台对象都会分配一些内存。 这个内存将在下一个tick时被垃圾收集器释放。 但是,如果你有一个太大的循环,下一个滴答声永远不会来。
但是我testing了这个:
setInterval(function() { for (var i = 0; i < 100000; ++i) { console.log(i); } }, 10000)
根据谷歌小组讨论,在每个时间间隔之间,NodeJS垃圾收集器应该通过console.log释放分配的内存。 但事实并非如此。 每次循环运行时,我的进程需要更多的RAM。
我也testing了这个:
var fs = require('fs') var output = fs.createWriteStream('./stdout.log'); var errorOutput = fs.createWriteStream('./stderr.log'); var logger = new console.Console(output, errorOutput); var i = 0; for (;;) { logger.log(i++); }
行为是一样的。 这个过程需要更多的内存,直到它崩溃(因为更多的RAM可用)。 而stdout.log
文件总是空的。
最后,我testing了这个:
var fs = require('fs') var output = fs.createWriteStream('./stdout.log'); var errorOutput = fs.createWriteStream('./stderr.log'); var logger = new console.Console(output, errorOutput); setInterval(function() { for (var i = 0; i < 100000; i++) { logger.log(i); } }, 5000)
这个例子很有趣。 因为在每个时间间隔之间, stdout.log
被写入(行被追加到文件中)并且进程回收的RAM不会增长。 垃圾收集器在每个时间间隔之间进行工作。
我认为控制台对象不能很好地处理缓冲区。 但它仍然很奇怪。 如果你使用标准输出(只有一个console.log
),看起来控制台对象保存在内存中,打印到目前为止。 而且从来没有净化。 如果你使用文件输出,一切正常(除非你写在无限循环,当然)。
也许是因为NodeJS版本,我正在使用NodeJS 0.12.7
在nodejs存储库上打开一个问题后,我得到了以下答案 :
这是预期的行为: console.log是asynchronous的 ,与每个调用相关的内存不能被回收,直到事件循环的下一个滴答声。 在你的例子中,由于无限循环的缘故,下一个勾选不会发生。 如果您将您的示例重写为callback驱动的方法,则它会一直运行:
let i = 0; const next = () => process.stdout.write(`${i++}\n`, next); next();
在https://github.com/nodejs/node/issues/11568查看更多的细节讨论
另外,正如文档中所描述的,当stdoutredirect到文件时,控制台是同步的 。 但描述的行为仍然在这种情况下再现。
将console.log()
输出redirect到文件的无限循环不会使Node v4.x崩溃,而会导致Node v6崩溃。 这看起来像是在v6中引入的一个bug。
作为临时解决方法,可以使用控制台同步修补程序。
- 为什么在使用笑话testing节点应用程序时看不到控制台日志输出
- Node.js双重console.log输出
- 如何用console.log完全输出缓冲区内容
- 检查一个模块是否存在,如果是这样,用它replace控制台,否则不。 不工作,控制台得到未定义
- 节点与Chrome,将console.log分配给一个variables?
- 为什么使用Object.create()和console.log()时属性不显示?
- NodeJS与promise.catch和console.log的错误?
- 为什么Chrome会将引用types为Date的对象的原型视为“Object {}”,而不是“Date {}”?
- 如何使用“console.log”在NodeJS中使用命令行“Local heroku”在“Mac Terminal”中显示多行?