简单nodejs应用中的内存泄漏

Memory Leaks in simple nodejs app

本文关键字:内存 泄漏 nodejs 应用 简单      更新时间:2023-09-26

只是为了好玩和尝试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.");
}

我已经尝试了循环内外的变量。我试过在循环结束时将它们清空。没有什么可以改变内存泄漏

调查一下我的核心转储:

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

似乎这是一个关于console.log的已知问题,根据这个问题在github https://github.com/nodejs/node/issues/3171

这是一个已知的"问题",因为在a的情况下写入标准输出Tty/console是异步的。所以快速记录大量数据会非常如果tty/控制台,我们将在内存中缓冲大量写操作我跟不上了。

对于我来说,这里的代码似乎达到了50MB的峰值

以10000为一批执行该函数-使用setimate来处理下一批

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缓冲区进行某种形式的内部管理,否则这是不可能的。