写Java也得了解CPU–CPU缓存
现代CPU的缓存结构一般分三层,L1,L2和L3。如下图所示:
级别越小的缓存,越接近CPU, 意味着速度越快且容量越少。
L1是最接近CPU的,它容量最小,速度最快,每个核上都有一个L1 Cache(准确地说每个核上有两个L1 Cache, 一个存数据 L1d Cache, 一个存指令 L1i Cache);
L2 Cache 更大一些,例如256K,速度要慢一些,一般情况下每个核上都有一个独立的L2 Cache;
L3 Cache是三级缓存中最大的一级,例如12MB,同时也是最慢的一级,在同一个CPU插槽之间的核共享一个L3 Cache。
当CPU运作时,它首先去L1寻找它所需要的数据,然后去L2,然后去L3。如果三级缓存都没找到它需要的数据,则从内存里获取数据。寻找的路径越长,耗时越长。所以如果要非常频繁的获取某些数据,保证这些数据在L1缓存里。这样速度将非常快。下表表示了CPU到各缓存和内存之间的大概速度:
从CPU到 大约需要的CPU周期 大约需要的时间(单位ns)
寄存器 1 cycle
L1 Cache ~3-4 cycles ~0.5-1 ns
L2 Cache ~10-20 cycles ~3-7 ns
L3 Cache ~40-45 cycles ~15 ns
跨槽传输 ~20 ns
内存 ~120-240 cycles ~60-120ns
利用CPU-Z可以查看CPU缓存的信息:
在linux下可以使用下列命令查看:
有了上面对CPU的大概了解,我们来看看 缓存行(Cache line) 。缓存,是由缓存行组成的。一般一行缓存行有64字节(由上图”64-byte line size”可知)。所以使用缓存时,并不是一个一个字节使用,而是一行缓存行、一行缓存行这样使用;换句话说,CPU存取缓存都是按照一行,为最小单位操作的。
这意味着,如果没有好好利用缓存行的话,程序可能会遇到性能的问题。可看下面的程序:
publicclass L1CacheMiss {privatestaticfinalint RUNS =10;privatestaticfinalint DIMENSION_1 =1024*1024;privatestaticfinalint DIMENSION_2 =6;privatestaticlong[][] longs;publicstaticvoid main(String[] args)throwsException{Thread.sleep(10000);
longs =newlong[DIMENSION_1][];for(int i =0; i < DIMENSION_1; i++){
longs[i]=newlong[DIMENSION_2];for(int j =0; j < DIMENSION_2; j++){
longs[i][j]=0L;}}System.out.println("starting....");long sum =0L;for(int r =0; r < RUNS; r++){finallong start =System.nanoTime();//slow// for (int j = 0; j < DIMENSION_2; j++) {// for (int i = 0; i < DIMENSION_1; i++) {// sum += longs[i][j];// }// }//fastfor(int i =0; i < DIMENSION_1; i++){for(int j =0; j < DIMENSION_2; j++){
sum += longs[i][j];}}System.out.println((System.nanoTime()- start));}}}
以我所使用的Xeon E3 CPU和64位操作系统和64位JVM为例,如 这里 所说,假设编译器采用行主序存储数组。
64位系统,Java数组对象头固定占16字节(未证实),而long类型占8个字节。所以16+8*6=64字节,刚好等于一条缓存行的长度:
如32-36行代码所示,每次开始内循环时,从内存抓取的数据块实际上覆盖了longs[i][0]到longs[i][5]的全部数据(刚好64字节)。因此,内循环时所有的数据都在L1缓存可以命中,遍历将非常快。
假如,将32-36行代码注释而用25-29行代码代替,那么将会造成大量的缓存失效。因为每次从内存抓取的都是同行不同列的数据块(如longs[i][0]到longs[i][5]的全部数据),但循环下一个的目标,却是同列不同行(如longs[0][0]下一个是longs[1][0],造成了longs[0][1]-longs[0][5]无法重复利用)。运行时间的差距如下图,单位是微秒(us):
最后,我们都希望需要的数据都在L1缓存里,但事实上经常事与愿违,所以缓存失效 (Cache Miss)是常有的事,也是我们需要避免的事。
一般来说,缓存失效有三种情况:
1. 第一次访问数据, 在cache中根本不存在这条数据, 所以cache miss, 可以通过 prefetch 解决。
2. cache冲突, 需要通过补齐来解决(伪共享的产生)。
3. cache满, 一般情况下我们需要减少操作的数据大小, 尽量按数据的物理顺序访问数据。
相关推荐
"java管理windows系统内存_java释放内存缓存_java获得CPU使用率_系统内存_硬盘_进程源代码" 在Windows操作系统中,内存管理是一个非常重要的方面。Windows实现按需调页的虚拟内存机制,使得应用程序可以使用超过...
占服务器 cpu,内存资源,服务独占服务器 cpu,内存资源,自然就不存在资源争用的一个情 况,性能必然有所提升; 缓存接入之多级缓存实现及分布式部署落地实践 今日课程主题: 1、项目分离部署 2、分布式部署 3、多级...
枚举进程 线程 模块 句柄 取CPU信息 缓存 页文件信息等等
OHC-堆外缓存特征异步缓存加载器支持每个条目可选或默认TTL / expireAt 条目驱逐和到期没有单独的线程能够维护大量的高速缓存使用分块实现适合低开销的微小条目与Java 8和Java 11一起运行-对Java 7和更早版本的支持...
在java开发中如何解决缓存雪崩的问题,因为缓存失效导致数据未加载到缓存中,或者缓存同一时间大面积的失效 从而导致所有请求都去查询数据库,导致数据库CPU和内存负载过高,甚至宕机
本文主要谈谈CPU缓存对Java编程的影响,不涉及具体CPU缓存的机制和实现。 现代CPU的缓存结构一般分三层,L1,L2和L3。如下图所示: 级别越小的缓存,越接近CPU, 意味着速度越快且容量越少。 L1是接近...
详细的讲述了并发、高并发、CPU Cache、CPU多级缓存、CPU多级缓存 - 缓存一致性(MESI)、CPU多级缓存-乱序执行优化、Java内存模型(Java Memory Model,JMM)、并发的优势和风险...等等图文并茂详解
CPU多级缓存 为什么需要CPU cache : cpu的频率太快了,快到主存跟不上,这样在处理时钟周期内,CPU常常需要等待主存,浪费资源。 所以cache的出现,是为了缓解CPU和内存之间素的的不匹配问题 (结构 : cpu -> cache ...
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来...
浅谈Linux内核之CPU缓存.pdf
Cpu多级缓存的意义? 1)时间局部性:如果某一个数据被访问,那么不久的将来,它很可能被再次访问。 2)空间局部性:如果某个数据被访问,他们与他相邻的数据很快也有可能被访问 Cpu对Cache的状态? 用于保证多个Cpu...
CPU FIFO先进先出缓存算法测试,以后可改进
11-线程池 ThreadPoolExecutor 底层原理源码分析(上)-...15、CPU缓存架构详解&高性能内存队列Disruptor 实战 (1).pdf 16、常用并发设计模式精讲 (1).pdf designpattern.zip disruptor.zip forkjoin.zip jmm(1).zip
扒站java源码 Funiture 项目需要 JDK 1.7及以上 Maven 管理jar包 Mysql 数据库存储 Tomcat 运行用服务器 Redis 非必须, 缓存用, 可在配置中打开 Rabbit 非必须, 队列用, 可在配置打开 Zookeeper 非必须, 可在配置中...
扒站java源码 Funiture 项目需要 JDK 1.7及以上 Maven 管理jar包 Mysql 数据库存储 Tomcat 运行用服务器 Redis 非必须, 缓存用, 可在配置中打开 Rabbit 非必须, 队列用, 可在配置打开 Zookeeper 非必须, 可在配置中...
第2节并发基础2.1CPU多级缓存--缓存一致性·缓存一致性(MESI,Cache line的四种状态)M:Modified,被修改E:Exclusive,独享
扒站java源码 Funiture 项目需要 JDK 1.7及以上 Maven 管理jar包 Mysql 数据库存储 Tomcat 运行用服务器 Redis 非必须, 缓存用, 可在配置中打开 Rabbit 非必须, 队列用, 可在配置打开 Zookeeper 非必须, 可在配置中...
扒站java源码 Funiture 项目需要 JDK 1.7及以上 Maven 管理jar包 Mysql 数据库存储 Tomcat 运行用服务器 Redis 非必须, 缓存用, 可在配置中打开 Rabbit 非必须, 队列用, 可在配置打开 Zookeeper 非必须, 可在配置中...