JavaScript匿名函数的垃圾回收

16
如果我有这样一个函数:
function do(callback) {
  //do stuff
  callback();
}

然后我传入一个匿名函数:

do(function() { //do something else });

这个匿名函数在页面的生命周期内是否会被回收?如果不会,我如何才能使其可供垃圾回收?

我需要这样做吗?

var h = function() { //do something };
do(h);
delete h;

我需要担心这个问题吗?我正在构建一个寿命较长的Web应用程序,它会进行很多ajax调用,并保留对象一段时间,而且在导航时不需要页面刷新。因此,我正在尝试弄清楚是否可能会遇到内存泄漏的问题。


对我来说,我倾向于从没有删除我认为已经删除的对象的事件侦听器中获得最多的内存泄漏。这里还有其他与JS相关的内存泄漏帖子https://dev59.com/C2445IYBdhLWcg3wH2vH 您可能还想在这里查看https://dev59.com/Z3RA5IYBdhLWcg3wsgBP - mrk
2个回答

13

这个匿名函数唯一的引用是作为函数参数,当函数执行完毕后,引用也会消失,因此你的回调函数在那之后就可以被垃圾回收了。但是如果有其他东西获取了它的引用,例如使用闭包,就可能很容易地发生。

function doo(callback) {
    $.get(url, function() {
        // callback is visible here!
    });
    callback();
}
doo(function() { /* do something else */ });

callback(以及通过调用doo创建的整个作用域)必须保留在内存中,因为内部函数可以通过闭包引用它;只有当内部函数被垃圾回收时,它才能被垃圾收集,而由于该函数是jqXHR对象的属性,因此在该对象之前,必须对该对象进行垃圾回收,而谁知道这何时发生...

更新:您可以通过不将函数定义在其他函数内来避免不必要的闭包:

var func = function() {
    // callback is not visible here
}
function doo(callback) {
    $.get(url, func);
    callback();
}
doo(function() { /* do something else */ });

如果我在 doo 函数中这样做 var g = $; g.get...,那么回调函数会被收集吗?或者我该怎么做才能使你的示例可收集? - Jose
@Jose:用另一个名称代替 $ 没有任何有用的作用。我更新了我的答案,展示了如何避免使用闭包。当然,如果你可以在调用 doo 时总是重复使用相同的参数而不是每次创建一个匿名函数,那么这是解决问题的更简单的方法。 - Tgr
我认为你的意思是“var func = function()...”,而不是“var fun”... 或者$.get(url, func)需要更新。 - Crashalot
@Crashalot:已修复,谢谢。回头看,使用延迟可能更加优雅:function doo() { return $.get(url).then(function () {/*...*/}); }; doo().then(function() {/* do something else */}); - Tgr
如果callback变量被显式地使用,它将通过闭包可用,因此在上面的示例中,callback将被垃圾回收。 - losnir
1
@losnir,这取决于JS引擎。有些结构使得无法确定将使用哪些变量(例如http://jsfiddle.net/x8xL8dwq/)-现代浏览器以不同的方式评估包含此类结构的代码,而旧版本则不会。 - Tgr

2
请注意循环引用,否则浏览器的垃圾回收机制将清除这些引用。闭包非常容易创建循环引用,即使您离开创建它的页面,它也可能被困在内存中。因此,停留在屏幕上较长时间的Web应用程序尤其容易受到影响。
请查看此处的“内存泄漏”部分:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript
我设计了很多静态页面Web应用程序。我发现即使您不必清理对象和事件处理程序(即您确定没有循环引用),也不会有害。它通常只需要添加几行额外的代码,并且在编写代码时将内存使用和效率放在首位。对于Web开发人员来说,这是一种转变,因为我们通常不必在创建网站时考虑这种事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接