为什么需要高速缓存
我们知道 CPU 就是一个无情的执行指令的机器。计算机执行指令的过程分为:取指、译码、执行、写回等阶段,指令是存放在内存中,CPU 的取指令单元自动从内存中读取指令,然后加载到 CPU 中执行;执行过程中,通常也需要从内存中读取要计算的数据或者把计算结果写回内存。
随着技术的发展(摩尔定律),CPU 运行速度远远超过内存访问速度,这巨大的差异必将拖慢 CPU 的执行速度。为了平衡 CPU 与主存的性能差异,从而提高 CPU 的执行速度,高速缓存就开始出现了。
高速缓存的工作原理:局部性原理
时间局部性:如果一个数据被访问了,那么它在短时间内还会被再次访问。
空间局部性:如果一个数据被访问了,那么和它相邻的数据也很快会被访问。
利用时间局部性进行优化: 保存近期频繁被访问的主存单元的数据
利用空间局部性进行优化: 从主存中取回待访问的数据时,同时取回位置相邻的主存单元的数据;其实 Cache 是以数据块(Block)为单位和主存进行数据交换的。
高速缓存读取过程
高速缓存的读取过程可以参考下图:
可以得到这样的公式:平均访存时间 = 命中时间 + 失效率 * 失效代价
那么,减少平均访存时间的途径有如下 3 种:
- 降低命中时间;
- 降低失效率;
- 减少失效代价;
Cache 失效原因
- 义务失效:也成为冷启失效,即第一次访问某一数据块的时候,Cache缺失,这个其实是无法有效避免的。
- 容量失效:即Cache无法保存程序访问所需要的所有数据块,可以通过增加 Cache 容量的方式来缓解。
- 冲突失效:即多个存储器位置映射到同一个 Cache 的位置(映射策略);冲突时进行替换(替换算法)。
Cache和主存的映射关系
由于Cache的行比主存储器的块要少,因此需要一种算法实现主存块到Cache行的映射。
常用的映射方法有3种,直接映射,全相联映射和组相联映射。
-
最简单的映射方法是直接映射(Direct Mapping)技术,主存中的每个块映射到一个固定的Cache行中。
-
在全相联映射(Fully Associative Mapping)中,主存中的任何块都可以存放在Cache中的任何位置。Cache的管理通常需要使用替换算法(如LRU、FIFO等)来决定哪个块被替换。
-
组相联映射(Set Associative Mapping)是直接映射和全相联映射的结合。在这种方式中,Cache被分成多个组,每个组包含多个Cache行。每个主存块可以映射到特定组中的任意行。映射关系可以通过以下公式计算:
常见 Cache 替换算法
- 随机
- 轮转
- 最近最少使用
- ……
高速缓存写策略
“Cache 命中”时的写策略
- 写穿透:数据同时写入 Cache 和主存
- 写返回:数据只写入 Cache,仅当该数据块被替换时才将数据写回主存
“Cache”失效时的写策略
- 写不分配:直接将数据写入主存
- 写分配:将该数据所在的块读入 Cache 后,再讲数据写入 Cache
Cache容量:容量是越小越好好还是越大越好呢?
从成本的角度考虑,我们希望Cache容量足够小,以至于可以降低存储器的价格。
从性能的角度考虑,我们希望Cache可以足够大,如果所有数据都从速度较快的Cache中取得,就不需要从速度较慢的主存中获取,性能将会变好。
从硬件方面考虑,Cache越大,寻址所需要的电路就会越多,受限于集成电路制造技术,大的Cache反而会比小的Cache稍慢。
总结
高速缓存存储器是现代计算机系统中不可或缺的重要组件,它通过提高数据访问速度,显著提升了计算机的整体性能。本文是高速缓存的入门知识,更深入的了解请关注后续更新。