假设您有参考A -> B -> C -> D
。当您从B
删除对A
的引用时,您将离开一个孤立的对象链B -> C -> D
。
C
和D
是否会被垃圾收集,即使无法找到它们(因为没有B
的引用)?
我认为GC对此很聪明,并将解决任何此类依赖关系。
但是,我查看了LinkedList
课程的source code,发现了与此相反的内容。我注意到,当列表为clear()
时,对每个链接的所有引用都显式设置为null
,从而使其成为O(n)
操作。这样做有什么理由/好处吗?
答案 0 :(得分:11)
这确实看起来有点奇怪。也许明确拆解列表的原因是清除现有迭代器和子列表以及父列表的列表。
当然没有做更快的垃圾收集。垃圾收集器不会遍历无法访问的对象中的引用,因此将它们置零将不会有任何区别。
<强>更新强>
该方法的更新版本有以下评论:
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
因此,至少在某些情况下,似乎GC有一个好处。
假设较老一代中的Node
包含对年轻一代中对象(例如Node
或元素)的引用。在收集年轻一代时,该引用成为“根”,导致年轻代对象被保留,即使旧代Node
无法访问。这种状态持续到收集老一代。老一代很少被收集。
如果您遍历列表并将其拆除,则包含旧的变量 - &gt;新引用分配了null
。该分配的写屏障导致(立即或在GC时间)原始引用不再是“根”。因此,现在可以收集年轻一代中的对象,并且它不会最终“老化”给老一代(这提出了需要收集该代的时间)。
据推测,GC的好处超过了取消列表的成本...平均而言,或者在成本是灾难性的情况下。
有关更多信息,请参阅Jones和Lins的“用于动态内存管理的垃圾收集算法”。我的(第一版)副本见第7.5章。
一般来说,最好抛弃一个Collection
对象并重新开始,而不是将其清除以便重复使用。
答案 1 :(得分:2)
是的,C和D将被垃圾收集,假设B是唯一引用它们的东西。这是因为它们无法从图形到应用程序对象图的根对象。
我想在null
实现中标记LinkedList
的每个链接的原因是为了防止内存泄漏。 LinkedList
之外的某些内容可能会抓住头节点。如果发生这种情况,即使在LinkedList
被清除后,它也会使所有其他节点保持活动状态。