有一个带有广泛对象图的应用程序。该图主要由一组子图组成,这些子图通过唯一的参考连接到图的其余部分。但在内部,每个这样的子图在对象之间都有一些交叉引用。偶尔这样的子图需要被抛弃。仅仅将指向该子图的唯一引用设置为null以使其符合垃圾收集条件是否足够?
我担心的是内部交叉引用可能会“保护”整个子图从垃圾回收。换句话说,垃圾收集器是否足够明智,可以确定子图中的所有引用都不会离开子图的边界,因此可以清除整个子图。
答案 0 :(得分:18)
正如本SO question所述,循环引用管理良好。
Java不进行引用计数,它使用tracing garbage collection(例如标记和扫描,复制集合或其某种组合)。如果跟随所有活动引用以找出哪些对象是“可到达的”,那么它将清除所有其他对象。
对象中的引用本身不可访问不会影响可访问性,因此它们是否为空无关紧要。
关于唯一一种情况,其中设置对null的引用可能会产生重大影响,即在长时间运行的方法中丢弃一个非常大的对象。
在这种情况下,将null设置为图表的引用将有助于形成隔离岛(即使对于内部循环引用),如此article中所述。
您可以在The Truth About Garbage Collection中找到有关无法访问状态的更多详细信息:
<强>无法到达强>
当对象不再存在强引用时,对象进入无法访问状态 当对象无法访问时,它是收集的候选对象。
注意措辞:
仅仅因为一个对象是收集的候选者并不意味着它会立即
集。 JVM可以自由地延迟收集,直到对象立即需要使用该主题。
重要的是要注意,不仅任何强引用都会在内存中保存一个对象。这些必须是从垃圾收集根链接的引用。 GC根是一类特殊的变量,包括:
循环强引用不一定会导致内存泄漏。 考虑创建两个对象的代码,并将它们分配给彼此。
public void buidDog() {
Dog newDog = new Dog();
Tail newTail = new Tail();
newDog.tail = newTail;
newTail.dog = newDog;
}
在方法返回之前,buildDog
方法中的临时堆栈变量有强引用指向Dog
和Tail
。
buildDog
方法返回后,Dog
和Tail
都无法从根目录中访问,并且是收集的候选对象(尽管VM可能实际上不会无限期地收集这些对象时间)。
答案 1 :(得分:2)
是的 - 垃圾收集器可以处理循环引用等。
答案 2 :(得分:0)
JVM的运作理念是“不可达的岛屿”。如果存在互连对象的无法到达的“孤岛”,那么该对象集合就有资格进行垃圾收集。