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