Javascript / 垃圾收集器中的循环引用

Posted

技术标签:

【中文标题】Javascript / 垃圾收集器中的循环引用【英文标题】:Circular references in Javascript / Garbage collector 【发布时间】:2011-11-12 21:59:03 【问题描述】:

谁能详细解释一下 javascript 引擎如何处理循环引用?浏览器甚至node.js之间有很大区别吗?

我所说的是对象内的显式后退/下一个引用。例如:

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;

或者垃圾收集器会在这样的星座上照顾我们吗?

【问题讨论】:

【参考方案1】:

任何半体面的垃圾收集器都会处理循环。

只有在进行简单的引用计数时,循环才是问题。

大多数垃圾收集器不进行引用计数(既因为它无法处理循环,又因为它效率低下)。相反,他们只是从“根”(通常是全局变量和基于堆栈的变量)开始跟踪他们可以找到的每个引用,并将他们可以找到的所有内容标记为“可访问”。

然后他们简单地回收所有其他内存。

循环没有问题,因为它们只是意味着将多次到达同一个节点。在第一次之后,该节点将被标记为“可达”,因此 GC 将知道它已经存在,并跳过该节点。

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

简而言之,这不是您需要担心的事情。 我似乎记得 IE6 的 Javascript GC 实际上无法处理循环(我可能是错的,我已经有一段时间没有阅读它了,而且自从我接触 IE6 以来已经很久了),但在任何现代实现中,它都不是问题。

垃圾收集器的全部意义在于抽象出内存管理。如果你必须自己做这项工作,你的 GC 就坏了。

有关现代垃圾收集和使用的标记和清除算法的更多信息,请参阅MDN。

【讨论】:

google-styleguide.googlecode.com/svn/trunk/… 有错吗? @Sandro 再次阅读我的答案。 :) 一个理智的 GC 处理循环就好了。任何比 IE6 更新的东西都可以被认为是正常的。如果您需要支持 IE6,那么您必须担心它对循环的错误处理。显然,Google 的指南是在这样的假设下编写的,即必须支持此类损坏的浏览器,因此它们必须跳过一些额外的障碍。 @Sandro 在该示例中发生了一些特别的事情:DOM 元素是循环引用的一部分。通常,您会在关闭页面之前泄漏内存。但是,如果我没记错的话,当您离开时,IE 并不总是删除对 DOM 的引用。 (显然这样做破坏了一些页面?) Douglas Crockford mentions 这个IE6 flaw 也是。我认为现在我们可以认为它与大多数 Web 应用程序无关。

以上是关于Javascript / 垃圾收集器中的循环引用的主要内容,如果未能解决你的问题,请参考以下文章

Java 中的循环引用

Javascript的垃圾回收机制

JavaScript基础概念之----垃圾回收机制

简单说明PHP的垃圾收集机制是怎样的?

JVM-03

Java 垃圾收集与内存回收