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

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

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

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

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

我使用的是JDK 8

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

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

(此外,在典型条件下,LinkedList可能会超越ArrayList或ArrayDeque.有一些基准可以说明这一点.想出LinkList优于其他工作负载的工作负载并不困难,但它比人们想象的要少.)

我很惊讶地发现LinkedList的清晰操作将所有节点彼此取消链接并从所包含的元素取消链接.这是code in JDK 8的链接.此更改可以追溯到2003年,更改出现在JDK 5中.此更改由错误JDK-4863813跟踪.该更改(或稍早的更改)清除单个节点的下一个和上一个引用他们与名单没有联系.在该bug报告中还有一个测试案例,它有一些兴趣.

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

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

评论还说取消了节点的链接

is sure to free memory even if there is a reachable Iterator

这指的是一个有点病态的情况,如下所示:

// fields in some class
List<Obj> list = createAndPopulateALinkedList();
Iterator<Object> iterator;

void someMethod() {
    iterator = list.iterator();
    // ...
    list.clear();
}

迭代器指向链表的一个节点.即使列表已被清除,迭代器仍然使节点保持活动状态,并且由于该节点具有下一个和先前的引用,因此以前在列表中的所有节点仍然存活.取消链接clear()中的所有节点可以收集这些节点.我认为这是非常病态的,因为迭代器很少存储在字段中.通常,迭代器在单个方法中创建,使用和丢弃,通常在单个for循环中.

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

点赞