【问题标题】:Why is an ArrayList always faster than a LinkedList [duplicate]为什么 ArrayList 总是比 LinkedList 快 [重复]
【发布时间】:2021-12-19 09:03:15
【问题描述】:

昨天我在 Java 17 中运行了一个基准测试,在那里我反复创建了一个新的 Arraylist 和 Linkedlist,并向其中添加了 10.000.000 个元素。

根据 LinkedList 的性质,添加元素(创建 LinkedObject 并将其放在末尾)应该比添加到 ArrayList 快得多。 (将整个数组复制到另一个稍大的数组中。)

像 arraycopy() 这样的原生函数真的那么快吗? LinkedList 唯一擅长的是将两个 LinkedList 合并在一起。

【问题讨论】:

  • This answer 总结了为什么你基本上不应该使用LinkedList。甚至 Joshua Bloch(谁写了LinkedListnever users it
  • ArrayList 只有在重新分配时才需要复制,这种情况很少见。而且它不需要做任何簿记,或者为链接生成压缩引用,基本上只是 memset 到分配限制。 (JVM JIT 优化器可能不够聪明,无法优化多个重新分配并首先分配最终大小)。
  • @Nikolas:作为discussed in comments on the answer herePerformance differences between ArrayList and LinkedList 上接受的答案只是在中间插入,而不是在末尾,这就是在这种情况下使 ArrayList 变慢的原因,但不是在这种情况下案子。不是很好的重复,除非有其他答案确实涵盖了一般情况,或者包括这种情况。

标签: java arraylist linked-list benchmarking


【解决方案1】:

大多数时候,添加到 ArrayList不会分配新数组,因为当需要增长时,实现会将支持数组的大小增加 50%。 p>

从内存的角度来看,这可能听起来很浪费,但即使在最坏的情况下,ArrayList 使用的内存也比LinkedList 少 - 链表中的每个条目都需要一个对象头 + 3 个引用(prev/value /next),而在最坏的情况下,ArrayList 的每个条目只有 1.5 个引用(即使用的数组单元,加上 50% 尚未使用)。

任何人,根据我的计算,这意味着将 1000 万个条目添加到默认启动的 ArrayList 将导致大约 35 个数组复制操作,这不是很多。 (是的,System.arraycopy 很快。)

最后,如果您为阵列提供10_000_000 的初始容量,则将生成零个阵列副本。您可以尝试一下,看看复制的真正成本是多少。

【讨论】:

  • 有一个规范的问答 (Performance differences between ArrayList and LinkedList) 表明 ArrayList 的创建速度较慢。既然这不正确是有原因的,那么问答应该得到解决。
  • 35 个数组复制操作,但其中大多数仍然很小,因此不会将整个最终大小写入 36 次。 size * (1 + 1/1.5 + 1/1.5^2 ...) 收敛到大约 x 2 的大小。
  • @PeterCordes 接受的答案没有 wrong 并回答了那里提出的问题(尽管有标题,但重点是在中间添加和删除)。但是,它并没有解释这里导致这个问题的误解(ArrayLists 如何分配数组,以及以何种容量)。这在对更一般问题的回答中进行了解释。
  • @PeterCordes 我们可以轻松地模拟行为以获得确切的数字,即int copies = 0, copied = 0; for(int cap = 10; cap < 10_000_000; cap *= 1.5) { copies++; copied += cap; } System.out.println(copies + " copy operations, copied " + copied + " refs total");,为我们提供 27,690,301 个参考。然后,我们应该考虑LinkedList 在 Eden 空间中创建了 10M 大小为 5 到 6 个 refs 的节点对象,以便在下一次 GC 时复制到 Survivor 空间。这是ArrayList 的复制操作量的两倍,即使在第一次 GC 时节点被提升为旧代也是如此。
  • 想一想,即使是 10M 节点对象的 初始化 与标头和三个引用一起执行与数组初始化和 35 次复制操作一样多的内存写入(假设 JVM 能够优化Arrays.copyOf(…),如HotSpot)。
猜你喜欢
  • 1970-01-01
  • 2014-12-31
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
  • 2014-12-24
  • 2014-09-17
  • 2015-04-10
  • 2011-09-04
相关资源
最近更新 更多