JavaScript闭包中的垃圾收集

时间:2012-09-27 10:52:09

标签: javascript garbage-collection closures

我需要一些帮助来解决这是如何工作的(或者不是这样)。

  1. 在网页中,我为节点创建了一个click事件监听器。
  2. 在监听器中,我创建了一个随机类的实例,它将节点设置为自身内的属性。因此,如果var classInstance是实例,我可以像classInstance.rootNode那样访问节点。
  3. 当侦听器触发时,我设置了一个ajax请求,保持classInstance关闭并将ajax响应传递给classInstance并使用它来修改rootNode的样式或内容或其他。
  4. 我的问题是,一旦我完成classInstance,假设没有其他任何东西引用它本身,它在其自己的闭包中没有任何其他东西,垃圾收集器会处理它吗?如果没有,我该如何标记它以供处置?

2 个答案:

答案 0 :(得分:6)

为了回应@ Beetroot-Beetroot的疑虑(不可否认,我也有),我做了一些挖掘。我设置了this fiddle,并使用chrome dev-tools' timelinethis article作为指导。在小提琴中,两个几乎相同的处理程序创建一个带有2个日期对象的闭包。第一个仅引用a,第二个引用ab。虽然在这两种情况下都只能真正暴露a(硬编码值),但第一个闭包使用的内存要少得多。无论是JIC(只是及时编译)还是V8的JS优化魔法,我都不能肯定。但是从我读过的内容来看,我会说V8的GC在b函数返回时解除分配tst,而在第二种情况下则不能bar引用{{ 1}} b返回时)。我觉得这不是那么古怪,我一点都不会惊讶地发现FF甚至IE都会有类似的工作。
只是为了完整性而添加了这个,也许是无关紧要的更新,因为我觉得google文档中dev-tools的链接是增值的


这有点依赖,作为一个简单的经验法则:只要你不能再引用tst2变量,它就应该是GC,而不管它自己的循环引用。我已经测试了很多结构,类似于你在这里描述的结构。也许it's worth a look我发现封闭和内存泄漏并不常见或容易过去(至少,不再是)。

但正如接受的答案所说:几乎不可能知道什么时候会泄漏什么代码。
再次阅读你的问题,我会说:不,你不会泄漏内存:classInstance变量不是在全局范围内创建的,而是传递给各种函数(因此各种范围)。每次函数返回时,这些范围都会分解。 classInstance如果已被传递到另一个函数/范围,则不会被GC。但是,只要引用classInstance的最后一个函数返回,该对象就会标记为GC。当然它可能是一个循环引用,但它是一个参考,不能从任何地方访问,但它自己的范围。
你也不能真正称之为闭包:当外部范围存在某种形式的曝光时会发生闭包,这在你的例子中没有发生。

我在解释这样的东西时很垃圾,但回顾一下:

classInstance

GC会释放mem var foo = (function() { var a, b, c, d; return function() { return a; } })(); bc引用:它们已超出范围,无法访问它们......

d

在这种情况下,由于显而易见的原因,var foo = (function() { var a, b, c, d; return function() { a.getB = function() { return b; } a.getSelf = function() { return a;//or return this; } return a; } })(); //some code foo = new Date();// 也不会获得GC。 b公开fooa,其中b是包含循环引用的对象。虽然只要afoo = new Date()就会失去对foo的任何引用。当然,a仍然引用自己,但a不再暴露:它可以引用它喜欢的任何东西。大多数浏览器都不会关心GC aa。事实上,我已经检查过Chrome,FF, IE8所有GC上面的代码完全正确......不用担心,那么。

答案 1 :(得分:1)

我不是这个问题的专家,但我很确定GC 不会处理它。实际上,它可能永远不会,因为您在事件侦听器和DOM节点之间创建了一个循环引用。要允许它被垃圾收集,您应该将这些引用(事件监听器和/或rootNode)中的一个或两个设置为undefined或null。

但是,如果您正在创建许多这样的类实例,或者如果它可以在页面的生命周期内多次创建,我只会担心这一点。否则,这是一项不必要的优化。