关于清除链接列表的Java最佳实践

时间:2015-11-26 10:18:31

标签: java collections garbage-collection java-8

我正在编写数据结构java中的链表(为了我的学习,我没有使用任何标准的java库),我想通过null引用来清除数据结构。请建议我哪种方法更好

1)只需清空列表的开始引用即可。

2)除了取消启动之外,我将所有内部节点的所有下一个指针取消引用为null。这有助于垃圾收集器吗?

我看到方法2的混乱在JDK中遵循LinkedList实现。但我没有看到相同的TreeMap

我正在使用JDK 8

1 个答案:

答案 0 :(得分:2)

这是一个有趣的问题,答案历史悠久,有微妙的权衡。

简短的回答是,清除引用对于正确操作数据结构不是必需的。由于您正在学习数据结构,我建议您不要在自己的实现中担心此问题。我的预感(虽然我没有对此进行基准测试)是在清除所有链接节点时可能产生的任何好处在典型条件下很少会引起注意。

(此外,在典型情况下,LinkedList可能会优于ArrayListArrayDeque基准说明这一点。提出LinkedList优于其他工作负载的工作量并不困难,但它比人们想象的要少。)

我很惊讶地发现clear的{​​{1}}操作将所有节点彼此之间以及与所包含的元素断开链接。这是code in JDK 8的链接。此更改可以追溯到2003年,更改出现在JDK 5中。此更改由错误JDK-4863813跟踪。当它们从列表中取消链接时,该更改(或稍早的更改)将清除各个节点的下一个和上一个引用。在该错误报告中还有一个测试案例,它有一些兴趣。

问题似乎是可以对创建垃圾节点的LinkedList进行更改,比垃圾回收器可以回收它们更快。这最终会导致JVM内存不足。垃圾节点全部链接在一起的事实似乎也具有阻止垃圾收集器的效果,使得mutator线程更容易超过收集器线程。 (我不清楚让多个线程改变列表是多么重要。在测试用例中,它们都在列表上同步,因此没有实际的并行性。)对{{1的更改将节点彼此取消链接使收集器更容易完成其工作,因此显然使测试不再耗尽内存。

快进到2009年,当LinkedList代码被提升为"整容时。"这是由错误JDK-6897553跟踪并在此email review thread中进行了讨论。 "整容"的最初动机之一是将LinkedList操作从O(n)减少到O(1),因为取消链接所有节点对于该bug的提交者来说似乎是不必要的。 (这对我来说当然没必要!)但经过一些讨论后,决定取消链接行为为垃圾收集器提供了足够的好处,以保留它并记录它。

评论还说取消链接节点

  即使有可达的Iterator,

也一定会释放内存

这指的是一个有点病态的案例如下:

LinkedList

迭代器指向其中一个链表的节点。即使列表已被清除,迭代器仍然使节点保持活动状态,并且由于该节点具有下一个和先前的引用,因此以前在列表中的所有节点仍然存活。取消链接clear()中的所有节点可以收集这些节点。我认为这是非常病态的,因为迭代器存储在字段中很少见。通常,迭代器在单个方法中创建,使用和丢弃,通常在单个// fields in some class List<Obj> list = createAndPopulateALinkedList(); Iterator<Object> iterator; void someMethod() { iterator = list.iterator(); // ... list.clear(); } 循环内。

现在,关于clear()。我不认为for解除其节点链接的根本原因是TreeMap没有。LinkedList没有。有人可能会认为整个JDK代码库是一致的,所以如果TreeMap取消链接节点的良好做法,这也应该对LinkedList进行。唉,事实并非如此。最有可能发生的事情是客户遇到TreeMap的病态行为,并且在那里进行了更改,但没有人观察到与LinkedList类似的行为。因此没有动力更新TreeMap