如何防止node.js中的内存泄漏?

nee*_*ebz 45 memory-leaks node.js

我们知道node.js为我们提供了强大的力量,但强大的力量带来了巨大的责任.

据我所知,V8引擎不做任何垃圾收集.那么我们应该避免哪些最常见的错误,以确保没有内存从我的节点服务器泄漏.

编辑: 对不起我的无知,V8确实有一个强大的垃圾收集器.

Ray*_*nos 65

据我所知,V8引擎不做任何垃圾收集.

V8在构建中具有强大而智能的垃圾收集器.

您的主要问题是不了解闭包如何保持对外部函数的作用域和上下文的引用.这意味着有多种方法可以创建循环引用或以其他方式创建只是清理的变量.

这是因为您的代码是不明确的,并且编译器无法判断垃圾收集它是否安全.

强制GC获取数据的一种方法是使变量为空.

function(foo, cb) {
    var bigObject = new BigObject();
    doFoo(foo).on("change", function(e) {
         if (e.type === bigObject.type) {
              cb();
              // bigObject = null;
         }
    });
}
Run Code Online (Sandbox Code Playgroud)

v8如何知道在事件处理程序中垃圾收集大对象是否安全?它不是这样你需要通过将变量设置为null来告诉它不再使用它.

各种文章阅读:

  • 循环引用不应对"智能"GC造成最轻微的问题.即使是最简单的GC也可以处理它们(引用计数不是真正的GC).关于事件处理程序的提示似乎是正确的. (24认同)
  • @Raynos在我看来,将`bigObject`设置为`null`在这种情况下没有任何意义.删除事件处理程序本身将允许收集`bigObject`,这就是我们想要的.但是,对于*null*,`bigObject`引用只会在下一个处理程序调用时导致运行时错误. (5认同)
  • 这真的很好.雷诺斯说,还有其他各种方法来制造这样的问题; 有没有人对其他要注意的事情有很好的指导? (4认同)
  • @jwerre该功能永远不会完成.这是一个改变倾听者.只有当`doFoo(foo)`返回的事件发射器被垃圾收集时,该函数才会完成. (3认同)

duk*_*ave 24

我想说服自己接受的答案,特别是:

不了解闭包如何保持对外部函数的范围和上下文的引用.

所以我写了下面的代码来演示变量如何无法清理,人们可能会感兴趣.

如果您watch -n 0.2 'ps -o rss $(pgrep node)'在另一个终端中运行,您可以观察发生的泄漏.请注意,如果使用buffer = null 使用中的注释nextTick将允许该过程完成:

(function () {
    "use strict";

    var fs = require('fs'),
        iterations = 0,

        work = function (callback) {
            var buffer = '',
                i;

            console.log('Work ' + iterations);

            for (i = 0; i < 50; i += 1) {
                buffer += fs.readFileSync('/usr/share/dict/words');
            }

            iterations += 1;
            if (iterations < 100) {
                // buffer = null;

                // process.nextTick(function () {
                    work(callback);
                // });
            } else {
                callback();
            }
        };

    work(function () {
        console.log('Done');
    });

}());
Run Code Online (Sandbox Code Playgroud)

  • @dukedave我不确定这是不是一个很好的例子.遗憾的是,在递归函数调用结束之前,本地`buffer`变量无法获取垃圾,除非你明确地*null*它,但这种行为真的可以被认为是泄漏吗?当递归调用将结束时,所有局部变量自然都符合GC的条件,而不是*null*`buffer`.没有? (4认同)

小智 9

活动垃圾收集:

node --expose-gc test.js
Run Code Online (Sandbox Code Playgroud)

并用于:

global.gc();
Run Code Online (Sandbox Code Playgroud)

快乐编码:)

  • 手动调用垃圾收集器无助于实际的内存泄漏.无论如何,运行时周期性地调用垃圾收集器,并且GCed语言中的内存泄漏是由创建垃圾收集器无法安全收集的引用引起的.*但是*在调试时,经常调用gc可以大大提高信噪比,并且更容易判断你是否有真正的内存泄漏. (7认同)