Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/422.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 简单节点应用程序内存泄漏_Javascript_Node.js_Memory Leaks - Fatal编程技术网

Javascript 简单节点应用程序内存泄漏

Javascript 简单节点应用程序内存泄漏,javascript,node.js,memory-leaks,Javascript,Node.js,Memory Leaks,为了好玩和尝试nodejs,我写了一个非常非常简单的程序,测试Collatz猜想中的荒谬数字。从理论上讲,这应该是好的。我遇到的问题是,这个超级简单的代码存在内存泄漏,我无法确定原因 var step; var numberOfSteps; for (var i = 0; i < 100000000000000; i++) { step = i; numberOfSteps = 0; while (step !== 1) { if (step%2 =

为了好玩和尝试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.");
}
var阶跃;
var步骤数;
对于(变量i=0;i<1000000000000;i++){
步骤=i;
numberOfSteps=0;
while(步骤!==1){
如果(步骤%2==0)
步骤/=2;
其他的
步骤=3*步骤+1;
numberOfSteps++;
}
日志(“+i+”:“+numberOfSteps+”步骤“);
}

我尝试了循环内外的变量。我尝试在循环结束时将其置零。没有任何更改内存泄漏。

调查一点我的内核转储:

<--- 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)

131690毫秒:清除1398.1(1458.1)->1398.1(1458.1)MB,1.3/0毫秒(+2.8毫秒,自上一次GC以来分1步进行)[分配失败][增量标记延迟标记扫描]。
132935毫秒:标记扫描1398.1(1458.1)->1398.1(1458.1)MB,1245.0/0毫秒(+3.7毫秒,自标记开始以来分两步进行,最大一步为2.8毫秒)[最后手段gc]。
134169毫秒:标记扫描1398.1(1458.1)->1398.1(1458.1)MB,1234.5/0毫秒[最后的gc]。
==JS堆栈跟踪=========================================
安全上下文:0x33083d8e3ac1
1://*匿名*/[/user/projects/test.js:~1][pc=0x557d307b271](this=0x2A4 A669D8341

这是一个已知的“问题”,因为在 tty/控制台是异步的,所以非常快地记录大量数据可能会非常困难 如果tty/控制台 跟不上


这里的代码对我来说似乎达到了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);
函数collatz(n){
var步长,numberOfSteps,i;
对于(i=0;i<10000;i++,n++){
阶跃=n;
numberOfSteps=0;
while(步骤!==1){
如果(步骤%2==0)
步骤/=2;
其他的
步骤=3*步骤+1;
numberOfSteps++;
}
日志(“+n+”:“+numberOfSteps+”步骤“);
}
如果(n<1000000000000){
setImmediate(collatz,n);
}
}
科拉茨(1);
注意,在这种情况下,for循环可以从0开始,因为n将从1:p开始

我还没有尝试过更高的for循环值

我对原始代码做了一些基准测试——一次做100个(在for循环中)提供与10000相同的性能,并且在性能上与原始代码无法区分。即使每次10个,我也不会说这种方法有任何较慢的速度。只有每次1个,它始终比原始代码慢5-8%

注意,我最初认为问题是垃圾收集(或缺乏垃圾收集),因为这个紧密的循环没有给节点时间做任何家务,但是当我发布答案时,@Svabel发布了一个似乎是已知的问题,并使劲点击console.log

我只能假设使用
setImmediate
允许对tty缓冲区进行某种形式的内部管理,否则这是不可能的


泄漏在哪里?我在我的计算机上尝试过,我的内存只增加了不到0.01g没有泄漏…但是对于步骤===0,while循环是无限的…尽管如此,如果你解决了这个问题,节点似乎一直在缓慢地占用内存,不是吗是
控制台.log
导致的-这几乎就像GC无法运行一样要清理console.log callI留下的垃圾,在运行2-3分钟后,我的手机壳无法运行它,它坏了,并且崩溃了:
致命错误:调用并重试上次分配失败-内存不足进程中止(内核转储)
(内核转储更大)。虽然我在检查内存使用情况,但它增加了大约800mb,之后保持稳定,它继续运行,并在上面的内核转储中崩溃。这应该是从I=1开始的,我只是把我留下的数字放在那里。上面的数字决不能低于1。你能解释为什么使它异步解决了内存问题吗em?不是真的,我认为这可能是GC问题,但阅读@Svabel的答案,这可能与console.log的“已知问题”有关-我不想在我的答案中包含这一点,因为这似乎不太有趣,我在“问题”中看到了这一点,使用
setImmediate
是一个建议的解决方案-每次迭代一次setImmediate-每次迭代10000次是多余的,甚至100次都会给出与原始代码类似的“性能”(实际上在一些测试中,我不能说它更差),而每次迭代1次确实会对速度产生大约8%的影响