在Java并发编程中,我们经常会遇到共享变量的读写问题,关于这类问题我们经常会说到原子性、可见性、有序性这三大特性,再进一步会了解到总线和CPU的一、二、三级缓存。关于这三个级别的缓存网上文章介绍比较多,今天我们这篇文章,算是知识梳理与记录,也是总结与强化。
前言
本文并非是CPU缓存知识的大杂烩、大汇总,关于CPU三个级别缓存的讲解,如果细致地说,一篇文章可能说不清楚。同时,介绍一些比较“虚”的知识点,很多小伙伴并不感兴趣,比如CPU缓存的发展史,这就要涉及不同架构、不同型号的CPU的知识,这样罗列下来意义也不大。
所以,本篇文章重在讲解干货,让人一目了然,之后便能铭记于心,如果需要面试也能说得明白。
一、概述
下面这段文字来自百科:
CPU高级缓存,(英语:CPU Cache,在本文中简称缓存)是用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。
当处理器发出内存访问请求时,会先查看缓存内是否有请求数据。如果存在(命中),则不经访问内存直接返回该数据;如果不存在(失效),则要先把内存中的相应数据载入缓存,再将其返回处理器。
缓存之所以有效,主要是因为程序运行时对内存的访问呈现局部性(Locality)特征。这种局部性既包括空间局部性(Spatial Locality),也包括时间局部性(Temporal Locality)。有效利用这种局部性,缓存可以达到极高的命中率。
在处理器看来,缓存是一个透明部件。因此,程序员通常无法直接干预对缓存的操作。但是,确实可以根据缓存的特点对程序代码实施特定优化,从而更好地利用缓存。
CPU高速缓存我们一般称之为CPU缓存,或者缓存。通过上面这段文字,我们大致可以得出以下几点结论:
- 缓存是了减少处理器访问内存所需的时间。
- 缓存容量远小于内存,速度远大于内存,非常接近处理器。
- 处理器向内存发出访问请求时,先查看缓存,缓存命中则不经过内存直接返回数据;缓存未命中,则先把内存中数据再入缓存再返回处理器。这个原理与Redis和数据库的缓存使用操作方式是一致的。
- 有效利用局部性特征可以极大地提高缓存命中率
- 开发人员无法直接干预对缓存的操作,但是可以通过程序代码来优化缓存命中率。
CPU在缓存中找到有用的数据被称为命中,当缓存中没有CPU所需的数据时(这时称为未命中),CPU才访问内存。
CPU缓存的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。
二、CPU缓存简介
一级缓存的起源针对内存的速度瓶颈,英特尔为80386设计了高速缓存(Cache),采取预读内存的方法来缓解这个速度瓶颈。本来最初的设计,80386将内置L1 Cache,但由于工艺、成本、工期等等方面的限制,80386最后并没有内置L1 Cache,而是将专门开发的L1 Cache芯片放置在CPU之外的主板上,但从此以后,Cache就和CPU成为了如影随形的东西。
简单来说,一级缓存是英特尔针对内存的速度瓶颈,采取预读内存方法来设计的高速缓存。
一级缓存最初是放置在CPU之外的主板上的,后来随着工艺等方面的提高,一级缓存已经内置到CPU中内部并与CPU同速运行。
一级缓存内置在CPU内部,直接与CPU数据总线相连,传输速度接近于CPU处理速度。
这就是一级缓存。
用于存储数据的缓存部分通常被称为RAM,掉电以后其中的信息就会消失。RAM又分两种,其中一种是静态RAM(SRAM);另外一种是动态RAM(DRAM)。前者的存储速度要比后者快得多,我们现在使用的内存一般都是动态RAM。
CPU的L1级缓存通常都是静态RAM,速度非常的快,但是静态RAM集成度低(存储相同的数据,静态RAM的体积是动态RAM的6倍),而且价格也相对较为昂贵(同容量的静态RAM是动态RAM的四倍)。扩大静态RAM作为缓存是一个不太合算的做法,但是为了提高系统的性能和速度又必须要扩大缓存,这就有了一个折中的方法:在不扩大原来的静态RAM缓存容量的情况下,仅仅增加一些高速动态RAM做为L2级缓存。
二级缓存,它是为了协调一级缓存和内存之间的速度。
这就是二级缓存。
三级缓存是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,这进一步提高了CPU的效率。其运作原理在于使用较快速的储存装置保留一份从慢速储存装置中所读取数据且进行拷贝,当有需要再从较慢的储存体中读写数据时,缓存(cache)能够使得读写的动作先在快速的装置上完成,如此会使系统的响应较为快速。
最早先的CPU缓存是个整体的,而且容量很低,英特尔公司从Pentium时代开始把缓存进行了分类。当时集成在CPU内核中的缓存已不足以满足CPU的需求,而制造工艺上的限制又不能大幅度提高缓存的容量。因此出现了集成在与CPU同一块电路板上或主板上的缓存,此时就把 CPU内核集成的缓存称为一级缓存,而外部的称为二级缓存。一级缓存中还分数据缓存(Data Cache,D-Cache)和指令缓存(Instruction Cache,I-Cache)。二者分别用来存放数据和执行这些数据的指令,而且两者可以同时被CPU访问,减少了争用Cache所造成的冲突,提高了处理器效能。
英特尔公司在推出Pentium 4处理器时,用新增的一种一级追踪缓存替代指令缓存,容量为12KμOps,表示能存储12K条微指令。
注意:
此时如果说L1的大小就不能使用L1d和L1i相加得出L1的大小,我们分别说数据缓存大小是多少,指令缓存是多少。
随着CPU制造工艺的发展,二级缓存也能轻易的集成在CPU内核中,容量也在逐年提升。再用集成在CPU内部与否来定义一、二级缓存,已不确切。而且随着二级缓存被集成入CPU内核中,以往二级缓存与CPU大差距分频的情况也被改变,此时其以相同于主频的速度工作,可以为CPU提供更高的传输速度。
三、CPU缓存详解
3.1 一级缓存
一级缓存(Level 1 Cache)简称L1 Cache,位于CPU内核的旁边,是与CPU结合最为紧密的CPU缓存,也是历史上最早出现的CPU缓存。
一般来说,一级缓存可以分为一级数据缓存(Data Cache,D-Cache)和一级指令缓存(Instruction Cache,I-Cache)。一级数据缓存简写为L1d,一级指令缓存简写为L1i。
二者分别用来存放数据以及对执行这些数据的指令进行即时解码,而且两者可以同时被CPU访问,减少了争用Cache所造成的冲突,提高了处理器效能。目前大多数CPU的一级数据缓存和一级指令缓存具有相同的容量。
缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾。
3.2 L1、L2、L3大小对比
在服务器上我们可以使用命令lscpu来查看CPU的情况:
上图红框分别代表一级数据缓存、一级指令缓存、二级缓存和三级缓存以及它们对应的大小。
从图中我们也可以看到一级缓存非常小,只有几十kb,同时L1d和L1i的大小是相同的(这不是绝对的,但是我们一般可以这么说)。
二级缓存和三级缓存大小依次递增,当然它们之间的访问速度却是依次递减的。
下图是一张CPU与各个硬件之间速度与大小递进关系图。
通过上图我们可以得出以下结论:
- L1、L2、L3都是SRAM,即Static RAM,静态RAM,速度很快
- L1、L2、L3速度依次递减,容量依次递增,价格依次递减
- L1、L2、L3都是集成在CPU内部
- 我们常用的内存是DRAM,即dynamic RAM,动态RAM,速度较慢
L1的大小一般在4KB到64KB之间,像我们上面图中列出的L1d和L1i分别为32K,加在一起也就64K。一些高端CPU大小可以达到1-2MB。
L2一般以MB为单位,但其大小通常在 1024KB 到 8MB 之间,上图我们这个就是1024KB,也就是1MB。
说明:
有的地方说是256KB到8MB之间,说法不一,不过这个也不是关键,两种说法皆可。但是通常分为128KB、256KB、512KB、1MB、2MB等。
L3一般也是以MB为单位,大小通常在4MB到50MB之间,上图我们的就是36608/1024=35.75MB。
像公司一般的CPU配置也就是上面我的这种,差距不大,但是有一些可能就比较大了,比如做数仓、数据迁移的ETL服务器,就比较大了。不但CPU比较大,内存都几十几百GB。如下图所示。
3.3 二级缓存详解
L2Cache,即CPU的二级缓存。二级缓存是CPU性能表现的关键之一,在CPU核心不变化的情况下,增加二级缓存容量能使性能大幅度提高。而同一核心的CPU高低端之分往往也是在二级缓存上有差异,由此可见二级缓存对于CPU的重要性。
L1是一级缓存,通常内建于微处理芯片(Chip)中。比如,IntelMMX微处理器(microprocessor)本身是带有一个有32Kb的一级缓存。
L2(就是二级)缓存是在独立芯片(有可能是在一个扩展卡上)。
有这样一段说法:
从理论上讲,在一颗拥有二级缓存的CPU中,读取一级缓存的命中率为80%。也就是说CPU一级缓存中找到的有用数据占数据总量的80%,剩下的20%从二级缓存中读取。
由于不能准确预测将要执行的数据,读取二级缓存的命中率也在80%左右(从二级缓存读到有用的数据占总数据的16%)。那么还有的数据就不得不从内存调用,但这已经是一个相当小的比例了。
较高端的CPU中,还会带有三级缓存,它是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,这进一步提高了CPU的效率。
我们大致了解到它们之间数据命中的概率即可,也说明了二级缓存的重要性。
3.3 三级缓存
三级缓存是为读取二级缓存后未命中的数据设计的—种缓存,在拥有三级缓存的CPU中,只有约5%的数据需要从内存中调用,这进一步提高了CPU的效率。
其运作原理在于使用较快速的储存装置保留一份从慢速储存装置中所读取数据且进行拷贝,当有需要再从较慢的储存体中读写数据时,缓存(cache)能够使得读写的动作先在快速的装置上完成,如此会使系统的响应较为快速。
早期的三级缓存也是外置的,CPU升级之后都是内置在CPU中的。
L3缓存的应用可以进一步降低内存延迟,同时提升大数据量计算时处理器的性能。
降低内存延迟和提升大数据量计算能力对游戏软件都很有帮助。而在服务器领域增加L3缓存在性能方面仍然有显著的提升。如具有较大L3缓存的配置利用物理内存会更有效,故它比较慢的磁盘I/O子系统可以处理更多的数据请求。具有较大L3缓存的处理器提供更有效的文件系统缓存行为及较短消息和处理器队列长度。
不过对于一般的家用PC来说,三级缓存的作用不大,只是起到一个辅助作用。三级缓存主要用途还是在游戏上和服务器上。