只是为了好玩并尝试使用nodejs,我编写了一个非常非常简单的程序,用于测试Collatz猜想中是否存在荒谬的数字。从理论上讲,这应该没问题。我遇到的问题是这个超级简单的代码有内存泄漏,我无法确定原因。
var step;
var numberOfSteps;
for (var i = 0; i < 100000000000000; i++) {
step = i;
numberOfSteps = 0;
while (step !== 1) {
if (step%2 === 0)
step /= 2;
else
step = 3 * step + 1;
numberOfSteps++;
}
console.log("" + i + ": " + numberOfSteps + " steps.");
}
我已经尝试了循环内外的变量。我已经尝试在循环结束时将它们归零。什么都没有改变内存泄漏。
答案 0 :(得分:1)
调查我的核心转储:
<--- Last few GCs --->
131690 ms: Scavenge 1398.1 (1458.1) -> 1398.1 (1458.1) MB, 1.3 / 0 ms (+ 2.8 ms in 1 steps since last GC) [allocation failure] [incremental marking delaying mark-sweep].
132935 ms: Mark-sweep 1398.1 (1458.1) -> 1398.1 (1458.1) MB, 1245.0 / 0 ms (+ 3.7 ms in 2 steps since start of marking, biggest step 2.8 ms) [last resort gc].
134169 ms: Mark-sweep 1398.1 (1458.1) -> 1398.1 (1458.1) MB, 1234.5 / 0 ms [last resort gc].
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x33083d8e3ac1 <JS Object>
1: /* anonymous */ [/user/projects/test.js:~1] [pc=0x557d307b271] (this=0x2a4a669d8341 <an Object with map 0xf8593408359>,exports=0x33083d804189 <undefined>,require=0x33083d804189 <undefined>,module=0x33083d804189 <undefined>,__filename=0x33083d804189 <undefined>,__dirname=0x33083d804189 <undefined>)
3: _compile [module.js:413] [pc=0x557d304d03c] (this=0x2a4a669d8431...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Aborted (core dumped)
根据github https://github.com/nodejs/node/issues/3171上的这个问题,这似乎是关于console.log的已知问题
这是一个已知的“问题”,因为在a的情况下写入stdout tty / console是异步的。因此,非常快速地记录大量数据 如果tty / console,很多写入会在内存中缓冲 跟不上。
答案 1 :(得分:1)
这里的代码对我来说似乎达到了约50MB的峰值
这将执行大量10000的函数 - 使用setImmediate来处理下一批
function collatz(n) {
var step,numberOfSteps, i;
for(i = 0; i < 10000; i++, n++) {
step = n;
numberOfSteps = 0;
while (step !== 1) {
if (step%2 === 0)
step /= 2;
else
step = 3 * step + 1;
numberOfSteps++;
}
console.log("" + n + ": " + numberOfSteps + " steps.");
}
if (n < 100000000000000) {
setImmediate(collatz, n);
}
}
collatz(1);
注意,在这种情况下,你可以让for循环从0开始,因为n将从1开始:p
我还没有尝试过更高的for循环值
我已经针对原始代码进行了一些基准测试 - 一次做100个(在for循环中)提供与10000相同的性能,并且在性能上与原始代码无法区分。即使一次只有10个,我也不会说这个方法也慢。每次只有1个,它始终比原始代码慢5-8%
注意,我最初认为这个问题是垃圾收集(或缺乏垃圾收集),因为紧密的循环让节点没有时间做任何管家,但是当我发布答案时,@Svabel发布了似乎已知的内容难以触及console.log的问题。
我只能假设使用
setImmediate
允许对tty缓冲区进行某种管理,否则这是不可能的。