JavaScript中的内存泄漏和关闭 - 何时以及为何?

Gol*_*den 50 closures memory-leaks node.js

您经常在网上看到使用闭包是JavaScript中的大量内存泄漏源.大多数时候,这些文章都涉及混合脚本代码和DOM事件,其中脚本指向DOM,反之亦然.

我知道闭包可能是一个问题.

但是Node.js怎么样?在这里,我们自然没有DOM - 所以没有机会像浏览器一样有内存泄漏副作用.

关闭可能还有哪些其他问题?任何人都可以详细说明或指点我这方面的好教程吗?

请注意,此问题明确针对Node.js,而不是浏览器.

Rus*_*bot 36

这个问题询问类似的事情.基本上,我们的想法是,如果在回调中使用闭包,则应在完成后"取消订阅"回调,以便GC知道无法再次调用它.这对我来说很有意义; 如果你有一个关闭只是等待被调用,那么GC将很难知道你已经完成了它.通过从回调机制手动删除闭包,它将变为未引用并可用于收集.

此外,Mozilla发表了一篇关于在Node.js代码中查找内存泄漏的精彩文章.我假设如果你尝试他们的一些策略,你可以找到代表泄漏行为的部分代码.最佳实践很好,但我认为了解您的程序需求更有帮助,并根据您可以凭经验观察的内容提出一些个性化的最佳实践.

以下是Mozilla文章的快速摘录:

  • Jimb Esser node-mtrace,它使用GCC mtrace实用程序来分析堆使用情况.
  • Dave Pacheco node-heap-dump拍摄了V8堆的快照,并在一个巨大的JSON文件中将整个序列序列化.它包括用于遍历和调查JavaScript中生成的快照的工具.
  • 丹尼科茨的v8-profilernode-inspector为V8探查,并使用WebKit网络检查节点调试接口提供节点绑定.
  • 菲利克斯·格纳斯(Felix Gnass)同样禁用了保留者图表
  • FelixGeisendörfer的节点内存泄漏教程是关于如何使用v8-profiler和的简短而精彩的解释node-debugger,并且目前是大多数Node.js内存泄漏调试的最新技术.
  • Joyent的SmartOS平台,为您调试Node.js内存泄漏提供了大量工具

这个问题的答案基本上说你可以通过分配null闭包变量来帮助GC .

var closureVar = {};
doWork(function callback() {
  var data = closureVar.usefulData;
  // Do a bunch of work
  closureVar = null;
});
Run Code Online (Sandbox Code Playgroud)

函数内部声明的任何变量在函数返回时都会消失,在其他闭包中使用的变量除外.在这个例子中,closureVar必须在内存中直到callback()被调用,但谁知道什么时候会发生?调用回调后,可以通过将闭包变量设置为null来提示GC.

免责声明:正如您从下面的评论中看到的,有一些SO用户说这些信息已经过时且对Node.js无关紧要.我还没有明确的答案; 我只是发布了我在网上发现的内容.


bor*_*kur 10

你可以在David Glasser的博客文章中找到一个很好的例子和解释.

嗯,这是(我添加了一些评论):

var theThing = null;
var cnt = 0; // helps us to differentiate the leaked objects in the debugger
var replaceThing = function () {
    var originalThing = theThing;
    var unused = function () {
        if (originalThing) // originalThing is used in the closure and hence ends up in the lexical environment shared by all closures in that scope
            console.log("hi");
    };
    // originalThing = null; // <- nulling originalThing here tells V8 gc to collect it 
    theThing = {
        longStr: (++cnt) + '_' + (new Array(1000000).join('*')),
        someMethod: function () { // if not nulled, original thing is now attached to someMethod -> <function scope> -> Closure
            console.log(someMessage);
        }
    };
};
setInterval(replaceThing, 1000);
Run Code Online (Sandbox Code Playgroud)

originalThing在Chrome开发工具(时间线选项卡,内存视图,点击记录)中使用和不使用归零进行试用.请注意,上面的示例适用于浏览器和Node.js环境.

还要特别感谢Vyacheslav Egorov.