我必须承认这篇文章的标题有点吸引人。 我最近阅读了此博客文章 ,这是有关此主题的讨论和辩论的一个很好的摘要。

但是这次,我想尝试一种不同的方法来比较这两个众所周知的数据结构:使用硬件性能计数器 。

我不会进行微基准测试,也不能直接进行。 我不会使用System.nanoTime()计时,而是使用HPC(例如高速缓存命中/未命中)。

无需介绍这些数据结构,每个人都知道它们的用途以及实现方式。 我将研究重点放在列表迭代上,因为除了添加元素之外,这是列表最常见的任务。 同时也因为列表的内存访问模式是CPU缓存交互的一个很好的例子。

这是我的用于测量LinkedList和ArrayList的列表迭代的代码:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;import ch.usi.overseer.OverHpc;public class ListIteration
{private static List<String> arrayList = new ArrayList<>();private static List<String> linkedList = new LinkedList<>();public static void initializeList(List<String> list, int bufferSize){for (int i = 0; i < 50000; i++){byte[] buffer = null;if (bufferSize > 0){buffer = new byte[bufferSize];}String s = String.valueOf(i);list.add(s);// avoid buffer to be optimized awayif (System.currentTimeMillis() == 0){System.out.println(buffer);}}}public static void bench(List<String> list){if (list.contains("bar")){System.out.println("bar found");}}public static void main(String[] args) throws Exception{if (args.length != 2) return;List<String> benchList = "array".equals(args[0]) ? arrayList : linkedList;int bufferSize = Integer.parseInt(args[1]);initializeList(benchList, bufferSize);HWCounters.init();System.out.println("init done");// warmupfor (int i = 0; i < 10000; i++){bench(benchList);}Thread.sleep(1000);System.out.println("warmup done");HWCounters.start();for (int i = 0; i < 1000; i++){bench(benchList);}HWCounters.stop();HWCounters.printResults();HWCounters.shutdown();}
}

为了进行测量,我使用基于监督程序库的名为HWCounters的类来获取硬件性能计数器。 您可以在这里找到此类的代码。

该程序采用2个参数:第一个参数用于ArrayList实现或LinkedList之间的选择,第二个参数用于initializeList方法中使用的缓冲区大小。 此方法使用50K字符串填充列表实现。 每个字符串都是刚创建的,即将添加到列表中。 我们也可以根据程序的第二个参数分配一个缓冲区。 如果为0,则不分配缓冲区。
bench方法执行对列表中未包含的常量字符串的搜索,因此我们完全遍历了列表。

最后, main方法是执行列表的初始化,对基准方法进行预热并测量该方法的1000次运行。 然后,我们从HPC打印结果。

让我们在不带2 Xeon X5680的Linux上不分配缓冲区的情况下运行程序:

[root@archi-srv]# java -cp .:overseer.jar com.ullink.perf.myths.ListIteration array 0
init done
warmup done
Cycles: 428,711,720
Instructions: 776,215,597
L2 hits: 5,302,792
L2 misses: 23,702,079
LLC hits: 42,933,789
LLC misses: 73
CPU migrations: 0
Local DRAM: 0
Remote DRAM: 0
[root@archi-srv]# /java -cp .:overseer.jar com.ullink.perf.myths.ListIteration linked 0
init done
warmup done
Cycles: 767,019,336
Instructions: 874,081,196
L2 hits: 61,489,499
L2 misses: 2,499,227
LLC hits: 3,788,468
LLC misses: 0
CPU migrations: 0
Local DRAM: 0
Remote DRAM: 0

第一次运行是在ArrayList实现上,第二次是使用LinkedList。

  • 周期数是执行代码所花费的CPU周期数。 显然,LinkedList比ArrayList花费了更多的周期。
  • LinkedList的说明要高一些。 但这在这里并不重要。
  • 对于L2缓存访问,我们有一个明显的区别:与LinkedList相比,ArrayList的L2未命中率要高得多。
  • 从机械上讲,LLC命中对ArrayList非常重要。

进行此比较的结论是,列表迭代期间访问的大多数数据位于LinkedList的L2中,但位于ArrayList的L3中。

我对此的解释是,添加到列表中的字符串是在之前创建的。 对于LinkedList,这意味着它是本地的在添加元素时创建的Node条目。 我们在节点上有更多位置。

但是,让我们使用为每个新添加的String分配的中间缓冲区重新运行比较。

[root@archi-srv]# java -cp .:overseer.jar com.ullink.perf.myths.ListIteration array 256
init done
warmup done
Cycles: 584,965,201
Instructions: 774,373,285
L2 hits: 952,193
L2 misses: 62,840,804
LLC hits: 63,126,049
LLC misses: 4,416
CPU migrations: 0
Local DRAM: 824
Remote DRAM: 0
[root@archi-srv]# java -cp .:overseer.jar com.ullink.perf.myths.ListIteration linked 256
init done
warmup done
Cycles: 5,289,317,879
Instructions: 874,350,022
L2 hits: 1,487,037
L2 misses: 75,500,984
LLC hits: 81,881,688
LLC misses: 5,826,435
CPU migrations: 0
Local DRAM: 1,645,436
Remote DRAM: 1,042

这里的结果有很大的不同:

  • 循环的重要性提高了10倍。
  • 说明与以前相同
  • 对于缓存访问,ArrayList具有比先前运行更多的L2未命中/ LLC命中,但仍处于相同的数量级顺序。 相反,LinkedList具有更多的L2未命中/ LLC命中,但此外,还有相当数量的LLC未命中/ DRAM访问。 区别就在这里。

使用中间缓冲区,我们可以推开条目和字符串,这会产生更多的高速缓存未命中,并且最终还会访问DRAM,这比访问高速缓存要慢得多。

ArrayList在这里更可预测,因为我们彼此之间保持元素的局部性。

此处的内存访问模式对于列表迭代性能至关重要。 ArrayList比LinkedList更稳定,因为在每个元素添加之间进行任何操作,都可以使数据保持比LinkedList更本地。

还要记住,对数组进行迭代对于CPU而言效率要高得多,因为它可以触发硬件预取,因为访问模式是非常可预测的。

Java出现日历博客上的JCG合作伙伴 Jean-Philippe BEMPEL的参考: ArrayList与LinkedList 。

翻译自: https://www.javacodegeeks.com/2013/12/arraylist-vs-linkedlist.html

ArrayList与LinkedList相关推荐

  1. 比较ArrayList、LinkedList、Vector

    翻译人员: 铁锚 翻译时间: 2013年12月2日 原文链接: ArrayList vs. LinkedList vs. Vector 1. List概述 List,就如图名字所示一样,是元素的有序列 ...

  2. java arraylist和list_Java中ArrayList和LinkedList区别

    原文链接:http://pengcqu.iteye.com/blog/502676 一般大家都知道ArrayList和LinkedList的大致区别: 1.ArrayList是实现了基于动态数组的数据 ...

  3. arraylist 后往前遍历_面试官:谈谈常用的Arraylist和Linkedlist的区别

    Arraylist:底层是基于动态数组,根据下表随机访问数组元素的效率高,向数组尾部添加元素的效率高:但是,删除数组中的数据以及向数组中间添加数据效率低,因为需要移动数组. 例如最坏的情况是删除第一个 ...

  4. ArrayList与LinkedList区别

    1.ArrayList实现了基于动态数组的数据结构,LinkedList是实现了基于链表的数据结构. 2.对于随机访问get/set,ArrayList优于LinkedList,因为LinkedLis ...

  5. 某团技术拷问:ArrayList 和 LinkedList 哪个更占空间?

    HR力荐了一个工作 4 年,目前年薪 40W+ 的候选人. 看他简历,从 JVM.MySQL.Redis,再到悲观锁.乐观锁一个都不缺,并发编程.分布式也都接触过,像是个实力派! 着急用人,就赶紧叫人 ...

  6. java什么时候用list_Java快问快答:用 ArrayList 还是 LinkedList?

    问题: 通常我会这么定义列表: List names = new ArrayList<>() names类型使用List接口,那么具体实现该如何选择. 什么时候应该用LinkedList替 ...

  7. 当面试官问我ArrayList和LinkedList哪个更占空间时,我这么答让他眼前一亮

    前言 今天介绍一下Java的两个集合类,ArrayList和LinkedList,这两个集合的知识点几乎可以说面试必问的. 对于这两个集合类,相信大家都不陌生,ArrayList可以说是日常开发中用的 ...

  8. 面试官:兄弟,说说 ArrayList 和 LinkedList 有什么区别

    作者 | 沉默王二 来源 | 沉默王二(ID:cmower) ArrayList 和 LinkedList 有什么区别,是面试官非常喜欢问的一个问题.可能大部分小伙伴和我一样,能回答出"Ar ...

  9. 深入理解java中的ArrayList和LinkedList

    杂谈最基本数据结构--"线性表": 表结构是一种最基本的数据结构,最常见的实现是数组,几乎在每个程序每一种开发语言中都提供了数组这个顺序存储的线性表结构实现. 什么是线性表? 由0 ...

  10. ArrayList和LinkedList区别

    ArrayList和LinkedList是两个集合类,用于存储一系列的对象引用(references).例如我们可以用ArrayList来存储一系列的String或者Integer.那么ArrayLi ...

最新文章

  1. spring data redis 使用之 spring boot 2.x
  2. 一个优秀的Push平台,需要经历怎样的前世今生
  3. 【年度盘点】最受欢迎的5大Java练习项目
  4. MyEclipse 6.5安装maven插件
  5. Linux进程之间通信 消息队列
  6. 数理统计的统计量分布t分布_t分布:啤酒厂发现的关键统计概念
  7. 1002.ubuntu系统级BUG-/dev/ttyUSB0
  8. Python编写只允许实例化一个对象的类
  9. linux查看图片的拍摄时间,ImageMagick 的一些高级图片查看技巧 | Linux 中国
  10. Oracle导入Excel中数据
  11. msxml3.dll 错误'800c0005' 系统未找到指定的资源错误
  12. 风控决策引擎——决策流构建实战
  13. SQLI DUMB SERIES-6
  14. 使用JACOB给WORD添加水印
  15. 北京游玩攻略,-怎么游玩清华北大
  16. 参考C++高级进阶教程
  17. 诛仙一直服务器维护,服务器维护《诛仙3》官方致仙友的一封信
  18. 最近失业了,在做副业的路上走了很多坑
  19. 将汉字转换为拼音或者翻转
  20. K均值聚类的理解和实现

热门文章

  1. spring-kafka整合:DefaultKafkaProducerFactory默认kafka生产者工厂介绍
  2. shell脚本启动kafka集群的多台节点
  3. 独家:这也许是最具珍藏价值的Oracle DBA生存宝典!
  4. 世界是沙粒还是宇宙_看到一个沙粒世界:再一次你好世界
  5. jvm jstat_使用jstat的JVM统计信息
  6. tdd 单元测试_何时给定在单元测试和TDD中的重要性
  7. activiti 变量_如何在Activiti中使用瞬态变量
  8. app访问java web_Java Web App体系结构
  9. java 事件通知_正确获取Java事件通知
  10. intellij ide_UltraESB的首选IDE – IntelliJ IDEA