垃圾收集 – 孤立的LinkedList链接
假设您有参考A -> B -> C -> D
当您从A
删除对B
的引用时,您将留下对象B -> C -> D
的孤立链。
C
和D
会被垃圾收集,即使没有办法到达它们(因为没有提到B
)?
我认为GC对此很聪明,并将解决任何此类依赖关系。
但是,我查看了LinkedList
类的源代码 ,发现了与此相反的内容。 我注意到当列表clear()
,对每个链接的所有引用都显式设置为null
,从而使其成为O(n)
操作。 这样做有什么理由/好处吗?
这确实看起来有点奇怪。 也许明确拆解列表的原因是清除现有迭代器和子列表以及父列表的列表。
肯定没有做更快的垃圾收集。 垃圾收集器不会遍历无法访问的对象中的引用,因此将它们置零将不会产生任何差别。
UPDATE
该方法的更新版本具有以下注释:
// 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
无法访问。 这种状态持续到收集老一代。 老一代很少被收集。
如果遍历列表并将其拆除,则包含旧 – >新引用的变量将被赋予null
。 该分配的写屏障导致(立即或在GC时间)原始引用不再是“根”。 因此,现在可以收集年轻一代中的对象,并且它不会最终“老化”给老一代(这提出了需要收集该代的时间)。
据推测,GC的好处超过了取消列表的成本……平均而言,或者在成本是灾难性的情况下。
有关更多信息,请参阅Jones和Lins的“用于动态内存管理的垃圾收集算法”。 我的(第一版)副本见第7.5章。
一般来说,最好抛弃一个Collection
对象并重新开始,而不是清除它以便重用。
是的,C和D将被垃圾收集,假设B是唯一引用它们的东西。 这是因为它们无法从图形到应用程序对象图的根对象。
我想在LinkedList
实现中将每个链接标记为null
的原因是为了防止内存泄漏。 LinkedList
之外的某些东西可以抓住头节点。 如果发生这种情况,即使已清除LinkedList
,它也会使所有其他节点保持活动状态。