在Nicholas Zakas的书中,他解释了在Javascript中使用引用计数进行垃圾收集时循环引用的问题。他使用以下示例:
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
}
解释这两个对象永远不会释放分配给它们的内存,因为它们在函数内部有两个对它们的引用。我想澄清一下这是如何运作的。
显然,每个对象有两个引用。第一个对象同时指向objectA
和objectB.anotherObject
。情况类似于第二个对象。所以每个对象的引用计数是2.但是当函数退出时会发生什么?书中没有真正描述过这一点。他说,只要对该值的引用被另一个值覆盖,引用计数就会递减。我认为这意味着:
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.someOtherObject = objectB;
objectB.anotherObject = objectA;
objectA.someOtherObject = objectA; //<-- that if I were to do this,
//the reference count of the second object (B)
//would become 1, and 3 for the first object (A).
}
但是当函数退出时会发生什么?据我所知,objectA
和objectB
及其相互引用的属性都将被销毁,因此,两个对象的引用计数将减少2.我看不到扎卡斯谈到的“循环参考问题”。有人可以解释他想说的话吗?
答案 0 :(得分:12)
据我了解,objectA和objectB以及它们各自引用的属性都将被销毁。
没有。 局部变量 objectA
和objectB
将被销毁(因为函数范围结束,没有闭包引用这些变量)。这意味着变量引用的对象中的引用计数每个都递减 1 。
如果对象的引用计数为0,则该对象将被销毁,并且它引用的所有其他内容将使其计数减少。但是对象的计数仍然是1
- 它们仍然相互引用 - 并且没有任何东西被破坏。
答案 1 :(得分:10)
引用计数和“循环”引用的“问题”在分配的对象包含对其他对象的引用时出现,但在活动分配中是未引用的。也就是说,在整个参考图中存在一些不活跃但仍然包含对其他非活动项目的引用的项目。
在您的示例代码中,当该函数退出时,对两个已分配对象没有活动引用,但对象相互引用,因此引用计数不为0.局部变量{{1并且objectA
将在函数的出口处消失(因为闭包本身就是垃圾),但是对象持有的内部引用保持它们的引用计数大于零。
这不是一个无法解决的问题,但它将引用计数这种简单的方法复杂化为垃圾收集技术。
请注意,没有规则或规范坚持JavaScript实现使用任何特定的垃圾收集技术。