CPU高速缓存如何减少处理器访问内存所需平均时间
扫描二维码
随时随地手机看文章
在计算机系统中,CPU高速缓存(英语:CPU Cache,在本文中简称缓存)是用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。当处理器发出内存访问请求时,会先查看缓存内是否有请求数据。如果存在(命中),则不经访问内存直接返回该数据;如果不存在(失效),则要先把内存中的相应数据载入缓存,再将其返回处理器。缓存之所以有效,主要是因为程序运行时对内存的访问呈现局部性(Locality)特征。这种局部性既包括空间局部性(Spatial Locality),也包括时间局部性(Temporal Locality)。有效利用这种局部性,缓存可以达到极高的命中率。在处理器看来,缓存是一个透明部件。因此,程序员通常无法直接干预对缓存的操作。但是,确实可以根据缓存的特点对程序代码实施特定优化,从而更好地利用缓存。
我们知道计算机中为了平衡CPU的寄存器和内存的速度差异,CPU 引入了高速缓存CPU Cache,前面我们介绍了什么是CPU Cache,以及CPU Cache的组织架构,本文我们来看看CPU Cache的是如何保证缓存一致性的?
系列文章:突破计算机性能瓶颈的利器CPU CacheCPU Cache是如何映射与寻址的?
单核CPU
在上一篇文章CPU Cache是如何映射与寻址的?中,我们介绍了CPU Cache的组织架构及其进行读操作时的寻址方式,但是缓存不仅仅只有读操作,还有写操作,这会带来一个新的问题:
当CPU是单核的情况下,CPU执行写入数据操作,当数据写入CPU Cache之后,此时CPU Cache数据会和内存数据就不一致了(这里前提条件:CPU Cache数据和内存数据原本是一致的),那么如何保证Cache和内存保持数据一致?
主要有两种写入数据的策略:
Write Through写直达
Write Back写回
Write Through写直达
Write Through写直达是一个比较简单的写入策略,顾名思义就是每次CPU执行写操作,如果缓存命中,将数据更新到缓存,同时将数据更新到内存中,来保证Cache 数据和内存数据一致;如果缓存没有命中,就直接更新内存
这个策略优点是简单可靠,但是速度较慢,可以从上图看出,每次写操作都需要与内存接触,此时缓存失去意义了,当然读操作时缓存还是能起作用的
Write Back写回
Write Back写回,也被称为延迟写入,相比于Write Through写直达策略每次写操作都需要内存参与;而Write Back策略则是,CPU向缓存写入数据时,只是把更新的cache区标记为dirty脏(即Cache Line增加 dirty脏 的标记位 ** ),即来表示该Cache Line的数据,和内存中的数据是不一致的,并不同步写入内存**
也就是说对内存的写入操作会被推迟,直到当这个Cache Line要被刷入新的数据时,才将Cache Line的数据回写到内存中
如今CPU Cache更多地采用write back写回的方式,写回的核心就是尽可能减少回写内存的次数,来提升CPU性能,缺点就是实现起来比较复杂
我们来看下它的具体流程是:当CPU发起写入操作请求时,如果缓存命中,就直接更新 CPU Cache 里面的数据,并把更新的Cache区标记为dirty脏
若缓存未命中的话,再判断缓存区已满或者定位到的Cache Line已被占用,缓存就会执行替换策略,常见的策略有:随机替换RR、先进先出FIFO、最近最少使用LRU等,我们后文再详细介绍;
当被替换的Cache Line被标记为脏,也就是该Cache Line的数据,和内存中的数据是不一致的,此时会触发操作:将Cache Line中的数据回写到内存中;然后,再把当前要写入的数据,写入到 Cache里,同时把Cache Line标记成脏
如果Cache Line的数据没有被标记成脏的、缓存区未满、定位到的Cache Line未被占用,那么直接把数据写入到 Cache 里面,同时把Cache Line标记成脏
随机替换 (Random Replacement,RR) ,顾名思义就是随机选择被替换的缓存块
实现简单,在缓存大小较大时表现良好,能够减少缓存替换的次数,提高缓存命中率
但是没有利用 “局部性原理”,无法提高缓存命中率;且算法性能不稳定,在缓存大小较小时,随机替换可能导致频繁的缓存替换,降低了缓存的命中率
FIFO
先进先出(First-In-First-Out, FIFO),根据数据进入缓存的顺序,每次将最早进入缓存的数据先出去,也就是先进入缓存的数据先被淘汰。
实现简单,适合短期的缓存数据;但不合适长期存储数据的场景,缓存中的数据可能早已经过时;当缓存大小不足时,容易产生替换过多的情况,从而降低了缓存的效率
FIFO 算法存在Belady贝莱迪现象:在某些情况下,缓存容量增大,命中率反而降低。概率比较小,但是危害是无限的
贝莱迪在1969年研究FIFO算法时,发现了一个反例,使用4个页框时的缺页次数比3个页框时的缺页多,由于在同一时刻,使用4个页框时缓存中保存的页面并不完全包含使用3个页框时保存的页面,二者不是超集子集关系,造成都某些特殊的页面请求序列,4个页框命中率反而低
CPU缓存的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为CPU运算速度要比内存读写速度快很多,这样会使CPU花费很长时间等待数据到来或把数据写入内存。 [1]缓存大小是CPU的重要指标之一,而且缓存的结构和大小对CPU速度的影响非常大,CPU内缓存的运行频率极高,一般是和处理器同频运作,工作效率远远大于系统内存和硬盘。实际工作时,CPU往往需要重复读取同样的数据块,而缓存容量的增大,可以大幅度提升CPU内部读取数据的命中率,而不用再到内存或者硬盘上寻找,以此提高系统性能。但是从CPU芯片面积和成本的因素来考虑,缓存都很小。按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。一般来说,每级缓存的命中率大概都在80%左右,也就是说全部数据量的80%都可以在一级缓存中找到,只剩下20%的总数据量才需要从二级缓存、三级缓存或内存中读取,由此可见一级缓存是整个CPU缓存架构中最为重要的部分。