为什么 Node.js 中的全局数组会导致内存泄漏?

Why does a global array in Node.js cause a Memory Leak?

我想了解 Node.js 中的垃圾收集是如何工作的。

创建了一个大数组并全局存储。在跟踪 Heap Usage 时,我发现一旦创建了数组,Heap Usage 就会急剧上升。难怪,因为数组很大。 但似乎垃圾收集器并没有删除数组——无论我等多久,堆使用率都保持不变。垃圾收集器认为,数组还需要吗?

let bigArray
setTimeout(function() {
    bigArray = new Array(9999999)
}, 5000)

setInterval(function () {
    const used = process.memoryUsage().heapUsed / 1024 / 1024;
console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
}, 1000)
```

垃圾收集器并非一直都在收集。仅当您的计算机 运行 内存不足时。

试试这个 post 并手动触发垃圾收集器。还会有内存泄漏吗?

How to request the Garbage Collector in node.js to run?

此外,该数组仍然被引用,如果您将它设置为 null 某处它可能会被收集。

该数组仍在模块函数闭包中引用,因此无法进行垃圾回收:

// Implicit closure created by nodejs
(function(exports, require, module, __filename, __dirname) {
   let bigArray
   setTimeout(function() {
      bigArray = new Array(9999999)
   }, 5000);

   setInterval(function () {
      // `bigArray` is still in scope here so cannot be garbage collected
      // If you set bigArray to undefined it will get GC'd
      const used = process.memoryUsage().heapUsed / 1024 / 1024;
      console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
   }, 1000);
});

如果您只在 setTimeout 函数范围内声明变量,它将被 GC 处理,而无需您自己删除引用,例如

// Implicit closure created by nodejs
(function(exports, require, module, __filename, __dirname) {
   setTimeout(function() {
      let bigArray = new Array(9999999)
   }, 5000);

   setInterval(function () {
      // `bigArray` is not in scope here so it will be GC'd
      const used = process.memoryUsage().heapUsed / 1024 / 1024;
      console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
   }, 1000);
});

此外,请注意,当 V8 不受内存限制时,它可能会表现得很懒惰。

您可以尝试 运行 您的脚本 --expose-gc 并强制 gc:

node --expose-gc index.js
const forceGC = () => {
    if (global.gc) {
        global.gc();
    } else {
        console.warn('No GC hook! Start your program as `node --expose-gc file.js`.');
    }
}

let bigArray
setTimeout(function() {
    bigArray = new Array(9999999)
}, 5000)

setInterval(function () {
    bigArray = undefined;
    forceGC();
    const used = process.memoryUsage().heapUsed / 1024 / 1024;
    console.log(`Usage: ${Math.round(used * 100) / 100} MB`);
}, 1000)

另外,您可以给节点更少的内存来测试它在 运行 内存不足时的行为:

node --max-old-space-size=100 index.js // Give node just 100MB (defaults to 2GB)