30

有人可以详细解释Javascript引擎如何处理循环引用?浏览器甚至node.js有很大的区别吗?Javascript /垃圾回收器中的循环引用

我在说的是对象内的明确的后/后引用。例如:

var objA = { 
    prop: "foo", 
    next: null 
}; 

var objB = { 
    prop: "foo", 
    prev: null 
}; 

objA.next = objB; 
objB.prev = objA; 

我们走了。如果我们做一个console.log(objA)我们可以看到我们创建了一个无限的链。 最大的问题是,这不好吗?未明确清理时是否会造成内存泄漏?

那么我们必须

objA.next = null; 
objB.prev = null; 

或将垃圾收集在这样的星座照顾我们?

回答

53

任何半面体垃圾收集器都会处理周期。

如果您进行天真的引用计数,周期只是一个问题。

大多数垃圾收集器不会进行重新计数(因为它无法处理循环,并且效率低下)。相反,他们只需遵循他们可以找到的每个参考,从“根”(通常是全局变量和基于堆栈的变量)开始,并将他们可以找到的所有内容标记为“可达”。

然后他们只是回收所有其他内存。

周期没有问题,因为它们只是表示同一个节点将被多次访问。在第一次之后,节点已经被标记为“可达”,并且GC将知道它已经在那里,并跳过该节点。

基于引用计数的更原始的GC通常实现检测和中断周期的算法。

总之,这不是你必须担心的。我似乎记得IE6的Javascript GC实际上没有处理周期(我可能错了,自从我阅读它已经有一段时间了,而且自从我碰到IE6以来已经很长时间了),但是在任何现代实现中,它都是没问题。

垃圾回收器中的整个点是抽象出内存管理。如果你必须自己做这个工作,你的GC坏了。

请参阅MDN了解更多关于现代垃圾收集和所使用的标记 - 扫描算法的信息。

+1

http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Closures那该怎么办? – Sandro

+2

@Sandro再次阅读我的答案。 :)一个理智的GC处理周期就好了。所有比IE6更新的东西都可以被认为是理智的。如果你需要支持IE6,那么你不得不担心它的循环处理中断。显然,Google的指南是在这样的假设下编写的,即必须支持这些破碎的浏览器,所以他们不得不跳过一些额外的环节。 – jalf

+0

@Sandro在这个例子中有一些特殊的情况:DOM元素是循环引用的一部分。一般来说,你会泄漏内存,直到你关闭页面。但是,如果我记得正确,那么当您离开时,IE并不总是删除对DOM的引用。 (显然这样做打破了一些页面?) –