5.高速缓冲存储器
程序访问的局部性原理
- 时间局部性是指在最近的末来要用到的信息,很可能是现在正在使用的信息
- 空间局部性是指在最近的未来要用到的信息,很可能与现在正在使用的信息在存储空间上是邻近的
基本工作原理
- Cache 位于存储器层次结构的顶层,通常由SRAM 构成
- 仅保存主存中最活跃的若干块的副本
- 地址映射以及替换算法的实现过程全部由硬件实现
提示
- CPU 与 Cache 之间的数据交换以字为单位,而 Cache 与主存之间的数据交换则以 Cache 块为单位。
- 操作系统中也会将主存中的一个块称为页,页面,页框,cache中的块也被称之为行

注意
某些计算机中也来用同时访问 Cache 和主存的方式,若 Cache 命中,则主存访问终止; 否则访问主存并替换 Cache。
Cache 和主存的映射方式
- 在 Cache 中要为每块加一个标记,指明它是主存中哪一块的副本
- 每个Cache 行需要一个有效位,说明 Cache 行中的信息是否有效
直接映射

地址结构为
| 标记 | Cache 行号 | 块内地址 |
|---|
装入cache位数
Cache和块内地址是装入Cache的

CPU访存过程
- 首先根据访存地址中间的c位,我到对应的 Cache 行,将对应 Cache 行中的标记和主存地址的高t位标记进行比较,若相等且有效位为1,则访问 Cache “命中”,此时根据主存地址中低位的块内地址,在对应的 Cache 行中存取信息
- 若不相等或有效位为0,则“不命中”,此时 CPU 从主存中读出该地址所在的一块信息送到对应的 Cache 行中,将有效位置 1,并将标记设置为地址中的高t位,同时将该地址中的内容送CPU。
提示
直接映射中主存容量与 Cache容量的比值 表示标记位的位数[1]
全相联映射
- 主存中的每一块可以装入 Cache 中的任何位置
- 需采用昂贵的按内容寻址的相联存储器进行地址映射
地址结构为
| 标记 | 块内地址 |
|---|

组相联映射
组间采用直接映射、而组内采用全相联映射
地址结构为
| 标记 | 组号 | 块内地址 |
|---|

CPU访存过程
- 首先根据访存地址中间的组号找到对应的 Cache 组
- 将对应 Cache 组中每个行的标记与主存地址的高位标记进行比较;若有一个相等且有效位为 1,则访问 Cache 命中, 此时根据主存地址中的块内地址,在对应 Cache 行中存取信息;
- 若都不相等或虽相等但有效位为0,则不命中,此时 CPU 从主存中读出该地址所在的一块信息送到对应 Cache 组的任意一个空闲行中,将有效位置1,并设置标记,同时将该地址中的内容送 CPU。
Cache 中主存块的替换算法
随机算法(RAND)
先进先出算法(FIFO)
近期最少使用算法(LRU)
LRU 算法对每个 Cache 行设置一个计数器,用计数值来记录主存块的使用情况,并根据计数值选择淘汰某个块,计数值的位数与 Cache 组大小有关[2],2路时有一位LRU 位,4路时有两位LRU 位。

抖动
当集中访问的存储区超过 Cache 组的大小时,命中率可能变得很低,如上例的访问序列变为1,2,3,4,5,1,2,3,4,5,⋯,而 Cache 每组只有4行,那么命中率为0,这种现象称为抖动
手算过程
从后往前看,哪一个出现次数是距离最远的,则为需要被替换掉的
最不经常使用算法(LFU)

提示
LFU算法一一曾经被经常访问的主存块在未来不一定会用到(如:微信视频聊天相关的块)并没有很好地遵循局部性原理,因此实际运行效果不如LRU
《计算机组成原理考研复习指导》## Cache 写策略
Cache 写命中
全写法(写直通法、write-through)
当 CPU 对Cache 写命中时,必须把数据同时写入Cache 和主存。
写缓冲
为减少全写法直接写入主存的时问损耗,在Cache 和主存之间加一个写缓冲(Write Buffer)。写缓冲是一个 FIFO 队列,写缓冲可以解决速度不匹配的问题。但若出现频繁写时,会使写缓冲饱和溢出。
回写法(write-back)
当 CPU 对 Cache 写命中时,只把数据写入 Cache,而不立即写入主存,只有当此块被换出时才写回主存。
为了减少写回主存的开销,每个 Cache 行设置一个修改位(脏位)。
Cache 写不命中
写分配法(write-allocate)
加载主存中的块到 Cache 中,然后更新这 个 Cache 块。它试图利用程序的空间局部性,但缺点是每次不命中都需要从主存中读取一块。
非写分配法(not-write-allocate)
只写入主存,不进行调块。
提示
非写分配法通常与全写法合用,写分配法通常和回写法合用
注
- 统一 Cache 的优点是设计和实现相对简单,但由于执行部件存取数据时,指令预取部件要从同一 Cache 读指令,会引发冲突。采用分离 Cache 结构可以解决这个问题,而且分离的指令和数据 Cache 还可以充分利用指令和数据的不同局部性来优化性能
- 现代计算机的 Cache 通常设立多级 Cache
