JavaScript中的垃圾回收是如何工作的?

30

JavaScript中的垃圾回收是如何工作的?它与.NET的垃圾回收类似吗?人们是否避免使用VBScript,而选择了JavaScript作为他们的标准客户端语言,是因为VBScript中的垃圾回收实现较差?


2个回答

81

垃圾回收是如何工作的?

简短回答是:当一块内存(比如一个对象)不再被引用时,它就可以被回收。具体何时、如何以及是否回收完全取决于实现方式,不同的实现方式也不同。但在语言层面上,这是自动完成的。

例如:

function foo() {
    var bar;

    bar = new ReallyMassiveObject();
    bar.someCall();
}

foo返回时,因为没有任何引用指向它,所以bar指向的对象会自动被垃圾回收。

与下面的情况形成对比:

function foo() {
    var bar;

    bar = new ReallyMassiveObject();
    bar.someCall();
    return bar;
}
// elsewhere
var b = foo();

现在对对象的引用在函数调用后仍然存在,并且持久存在,直到/除非调用者将其他内容分配给bb超出范围为止。

与之形成对比:

function foo() {
    var bar;

    bar = new ReallyMassiveObject();
    bar.someCall();
    setTimeout(function() {
        alert("Three seconds have passed");
    }, 3000);
}

即使在foo返回后,定时器机制仍然引用了定时器回调函数,而定时器回调函数(一个闭包)引用了创建它的上下文,该上下文还包含bar 变量。因此,理论上,当foo返回时,bar所引用的内容并不会立即被垃圾回收。相反,在定时器触发并释放对回调的引用之前,它将被保留,使得回调和它所引用的上下文都可以进行垃圾收集。 (实际上,现代JavaScript引擎可以并且确实优化其中的闭包。例如,在上述情况中,静态分析显示回调不引用bar,也不包含任何可能在运行时动态引用它的evalnew Function代码,因此JavaScript引擎可以安全地将bar排除在函数所引用的上下文之外,从而使其所引用的内容可以进行垃圾回收 - 现代引擎也确实这样做)。关于闭包的更多信息,请参见此文章

顺便说一下,JavaScript没有处理清除循环引用的问题,因此例如:

function foo() {
    var a, b;

    a = {};
    b = {};
    b.refa = a;
    a.refb = b;
}
foo返回时,ab互相引用并不是问题。由于没有其他东西引用它们两个,它们都可以被清理掉。但是在IE中,如果其中一个对象是主机提供的对象(例如DOM元素或通过new ActiveXObject创建的对象),而不是JavaScript对象,则情况就不同了。(因此,例如,如果您在DOM元素上放置JavaScript对象引用,并且JavaScript对象引用回DOM元素,则即使没有人引用它们两个,它们也会相互保留在内存中。)但这是IE的一个问题,而不是JavaScript的问题。
关于回复:
“是因为vbscript GC不好,人们才回到javascript作为他们标准的客户端api吗?”
JavaScript是最初的客户端网页脚本语言。VBScript只是后来随着微软推出浏览器而出现,并且只在微软浏览器中得到支持。如果你想使用最广泛的浏览器工作,JavaScript是唯一的客户端脚本游戏。它也是经典VBScript语言的八倍左右。;-)

5
简短回答是:这取决于平台。每个浏览器或JS虚拟机都可以自由地实现它们想要的方式。但这是一个很好的解释。 - haylem
2
@haylem:确实如此——但是有限制。平台不能以违反JavaScript作用域规则的方式回收东西。而一个从不回收任何东西的平台很可能会失败。 - T.J. Crowder
2
@T.J. Crowder:是的,但他们显然可以有自己的优化技巧和不同的引用计数方法。 - haylem
2
@haylem: 对的。*"何时、如何或是否回收完全取决于实现..."* - T.J. Crowder
1
@T.J.Crowder 确实,我错误地将http://www.informit.com/articles/article.aspx?p=26993中描述的情况与之联系起来,谢谢。 - TheBlastOne
显示剩余4条评论

2

垃圾回收在原则上在所有语言中使用类似的方法。然而,在不同的环境中实现将会有所不同(例如,每个浏览器都使用不同的方式来实现JavaScript GC)。对于Chrome的GC的非常简要的概述,请参见这里

至于VBScript,它被创建为只在IE中运行的JavaScript竞争/替代语言。当VBS被引入时,这是一个相当合理的决定 - IE占有90%以上的浏览器份额,看起来VBS可以取代(广泛支持的,较旧且功能较差)JavaScript;但现在情况已经不同了。此外,VBScript基本上是Visual Basic Lite,带有所有负面含义。


3
VBS是在1996年随IE一起推出的。当时Netscape占有约90%的浏览器市场份额。VBS为微软提供了与本地系统组件联系的方法,这在当时都是锁定用户的策略。 - Julian

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