有一个带有广泛对象图的应用程序.该图主要由一组子图组成,这些子图通过唯一的参考连接到图的其余部分.但在内部,每个这样的子图在对象之间都有一些交叉引用.偶尔这样的子图需要被抛弃.仅仅将指向该子图的唯一引用设置为null以使其符合垃圾收集的条件是否足够?
我担心的是内部交叉引用可能会"保护"整个子图从垃圾收集.换句话说,垃圾收集器是否足够明智,可以确定子图中的所有引用都不会离开子图的边界,因此可以清除整个子图.
如本SO问题所述,循环引用管理良好.
Java不进行引用计数,它确实使用跟踪垃圾收集(例如标记和扫描,复制集合或其某种组合).如果跟随所有活动引用以找出哪些对象是"可到达的",那么它将清除所有其他对象.
对象中的引用本身不可访问不会影响可访问性,因此它们是否为null无关紧要.
关于唯一一种情况,其中设置对null的引用可能会产生重大影响,即在长时间运行的方法中丢弃一个非常大的对象.
在这种情况下,将null设置为图形的引用将有助于形成隔离岛(即使对于内部循环引用),如本文所述.
您将在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
指向Dog
和Tail
.
在之后buildDog
方法返回时,Dog
并Tail
都成为从根本无法访问,并收集候选人(虽然VM可能没有实际收集这些物品进行无限期量).