垃圾回收 - 孤立的链接列表链接

2022-09-03 14:49:55

假设您有 参考资料 。删除 对 的引用时,将留下一个孤立的“对象”链。A -> B -> C -> DBAB -> C -> D

即使没有办法到达它们(因为没有提到),也会被垃圾收集?CDB

我想GC在这方面是聪明的,并且会解决任何此类依赖关系。

但是,我查看了该类的源代码,发现了与此信念相反的东西。我注意到,当一个列表被编辑时,对每个链接的所有引用都被显式设置为 ,从而使其成为一个操作。这样做有什么理由/好处吗?LinkedListclear()nullO(n)


答案 1

这看起来确实有点奇怪。也许它显式拆除列表的原因是,为了清除现有迭代器和子列表以及父列表的列表。

这样做当然不是为了让垃圾回收更快。垃圾回收器不会遍历无法访问的对象中的引用,因此将它们清空不会有任何区别。

更新

该方法的较新版本具有以下注释:

// 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似乎有好处。

假设老一辈中的 a 包含对年轻一代中的对象(例如 a 或元素)的引用。在收集年轻一代时,该参考成为“根源”,即使老一代无法到达,也会导致年轻一代的对象被保留。这种状态一直持续到老一辈人被收集为止。老一辈很少收集。NodeNodeNode

如果遍历列表并将其拆解,则会为包含旧 -> 新引用的变量分配一个 。该赋值的写入屏障会导致(立即或在 GC 时间)原始引用不再是“根”。因此,年轻一代的对象现在可以被收集,并且它不会最终“终身”给老一辈人(这带来了需要收集的那一代人的时间)。null

据推测,GC的好处超过了取消列表的成本......无论是在平均情况下,还是在成本灾难性的情况下。

有关更多信息,请参阅 Jones 和 Lins 的“用于动态内存管理的垃圾回收算法”。它在我的(第一版)副本的第7.5章中。


一般来说,最好扔掉一个对象并重新开始,而不是清除它以供重用。Collection


答案 2

是的,C 和 D 将被垃圾回收,假设 B 是唯一引用它们的东西。这是因为无法从关系图访问它们到应用程序对象图的根对象。

我想在实现中标记每个链接的原因是防止内存泄漏。外部的某个东西可能会抓住头节点。如果发生这种情况,即使清除了,它也会使所有其他节点保持活动状态。nullLinkedListLinkedListLinkedList