交叉引用和垃圾收集

时间:2008-11-07 08:33:04

标签: java

有一个带有广泛对象图的应用程序。该图主要由一组子图组成,这些子图通过唯一的参考连接到图的其余部分。但在内部,每个这样的子图在对象之间都有一些交叉引用。偶尔这样的子图需要被抛弃。仅仅将指向该子图的唯一引用设置为null以使其符合垃圾收集条件是否足够?

我担心的是内部交叉引用可能会“保护”整个子图从垃圾回收。换句话说,垃圾收集器是否足够明智,可以确定子图中的所有引用都不会离开子图的边界,因此可以清除整个子图。

3 个答案:

答案 0 :(得分:18)

正如本SO question所述,循环引用管理良好。

Java不进行引用计数,它使用tracing garbage collection(例如标记和扫描,复制集合或其某种组合)。如果跟随所有活动引用以找出哪些对象是“可到达的”,那么它将清除所有其他对象。

对象中的引用本身不可访问不会影响可访问性,因此它们是否为空无关紧要。

关于唯一一种情况,其中设置对null的引用可能会产生重大影响,即在长时间运行的方法中丢弃一个非常大的对象。

在这种情况下,将null设置为图表的引用将有助于形成隔离岛(即使对于内部循环引用),如此article中所述。

您可以在The Truth About Garbage Collection中找到有关无法访问状态的更多详细信息:

<强>无法到达

当对象不再存在强引用时,对象进入无法访问状态 当对象无法访问时,它是收集的候选对象。

注意措辞:
仅仅因为一个对象是收集的候选者并不意味着它会立即 集。 JVM可以自由地延迟收集,直到对象立即需要使用该主题。

重要的是要注意,不仅任何强引用都会在内存中保存一个对象。这些必须是从垃圾收集根链接的引用。 GC根是一类特殊的变量,包括:

  • 堆栈(任何线程)上的临时变量
  • 静态变量(来自任何类)
  • JNI原生代码的特殊引用

循环强引用不一定会导致内存泄漏。 考虑创建两个对象的代码,并将它们分配给彼此。

public void buidDog() {
   Dog newDog = new Dog();
   Tail newTail = new Tail();
   newDog.tail = newTail;
   newTail.dog = newDog;
}

在方法返回之前,buildDog方法中的临时堆栈变量有强引用指向DogTail

buildDog方法返回后,DogTail都无法从根目录中访问,并且是收集的候选对象(尽管VM可能实际上不会无限期地收集这些对象时间)。

答案 1 :(得分:2)

是的 - 垃圾收集器可以处理循环引用等。

答案 2 :(得分:0)

JVM的运作理念是“不可达的岛屿”。如果存在互连对象的无法到达的“孤岛”,那么该对象集合就有资格进行垃圾收集。