简体   繁体   English

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

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

I am trying to understand how the garbage collection in Node.js works.我试图了解 Node.js 中的垃圾收集是如何工作的。

A big array is created and stored globally.一个大数组被创建并全局存储。 When tracking the Heap Usage, I saw that once the array is created, the Heap Usage goes up drastically.在跟踪堆使用情况时,我看到一旦创建了数组,堆使用情况就会急剧上升。 No wonder, since the array is huge.难怪,因为数组很大。 But it seems like the garbage collector does not remove the array - no matter how long I wait, the Heap Usage stays the same.但似乎垃圾收集器不会删除数组 - 无论我等待多长时间,堆使用情况都保持不变。 Does the garabge collector think, the array is still needed?垃圾收集器是否认为,仍然需要数组?

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

The garbage collector does not collect all the time.垃圾收集器不会一直收集。 Only when your computer is running out of memory.仅当您的计算机用完 memory 时。

Try this post and trigger the garbage collector by hand.试试这篇文章并手动触发垃圾收集器。 Will it still have the memory leak?它还会有 memory 泄漏吗?

How to request the Garbage Collector in node.js to run? 如何请求 node.js 中的垃圾收集器运行?

Also the array is still referenced, if you set it to null somewhere it might get collected.此外,该数组仍被引用,如果您将其设置为 null,则它可能会被收集。

The array is still referenced in the module functions closure so can't be garbage collected:该数组仍然在模块函数闭包中引用,因此不能被垃圾收集:

// 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);
});

If you were to declare the variable only inside the setTimeout function scope it would be GC'd without having to remove the reference yourself, eg如果您仅在 setTimeout function scope 内声明变量,则无需自己删除引用即可进行 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);
});

Additionally, be aware that V8 could be behaving lazily when it's not constrained for memory.此外,请注意,当 V8 不受 memory 限制时,它可能会表现得很懒惰。

You can try running your script with --expose-gc and force gc:您可以尝试使用 --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)

Also, you can give node less memory to work with to test how it behaves when it's running low on memory:此外,您可以给节点更少的 memory 来测试它在 memory 上运行不足时的行为:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM