新手必备的高速缓存Cache入门知识

266 阅读4分钟

为什么需要高速缓存

我们知道 CPU 就是一个无情的执行指令的机器。计算机执行指令的过程分为:取指、译码、执行、写回等阶段,指令是存放在内存中,CPU 的取指令单元自动从内存中读取指令,然后加载到 CPU 中执行;执行过程中,通常也需要从内存中读取要计算的数据或者把计算结果写回内存。

随着技术的发展(摩尔定律),CPU 运行速度远远超过内存访问速度,这巨大的差异必将拖慢 CPU 的执行速度。为了平衡 CPU 与主存的性能差异,从而提高 CPU 的执行速度,高速缓存就开始出现了

高速缓存的工作原理:局部性原理

时间局部性:如果一个数据被访问了,那么它在短时间内还会被再次访问。

空间局部性:如果一个数据被访问了,那么和它相邻的数据也很快会被访问。

利用时间局部性进行优化: 保存近期频繁被访问的主存单元的数据

利用空间局部性进行优化: 从主存中取回待访问的数据时,同时取回位置相邻的主存单元的数据;其实 Cache 是以数据块(Block)为单位和主存进行数据交换的。

高速缓存读取过程

高速缓存的读取过程可以参考下图:

可以得到这样的公式:平均访存时间 = 命中时间 + 失效率 * 失效代价

那么,减少平均访存时间的途径有如下 3 种:

  1. 降低命中时间;
  2. 降低失效率;
  3. 减少失效代价;

Cache 失效原因

  1. 义务失效:也成为冷启失效,即第一次访问某一数据块的时候,Cache缺失,这个其实是无法有效避免的。
  2. 容量失效:即Cache无法保存程序访问所需要的所有数据块,可以通过增加 Cache 容量的方式来缓解。
  3. 冲突失效:即多个存储器位置映射到同一个 Cache 的位置(映射策略);冲突时进行替换(替换算法)。

Cache和主存的映射关系

由于Cache的行比主存储器的块要少,因此需要一种算法实现主存块到Cache行的映射

常用的映射方法有3种,直接映射,全相联映射和组相联映射。

  • 最简单的映射方法是直接映射(Direct Mapping)技术,主存中的每个块映射到一个固定的Cache行中。

  • 全相联映射(Fully Associative Mapping)中,主存中的任何块都可以存放在Cache中的任何位置。Cache的管理通常需要使用替换算法(如LRU、FIFO等)来决定哪个块被替换。

  • 组相联映射(Set Associative Mapping)是直接映射和全相联映射的结合。在这种方式中,Cache被分成多个组,每个组包含多个Cache行。每个主存块可以映射到特定组中的任意行。映射关系可以通过以下公式计算:

常见 Cache 替换算法

  1. 随机
  2. 轮转
  3. 最近最少使用
  4. ……

高速缓存写策略

“Cache 命中”时的写策略

  • 写穿透:数据同时写入 Cache 和主存
  • 写返回:数据只写入 Cache,仅当该数据块被替换时才将数据写回主存

“Cache”失效时的写策略

  • 写不分配:直接将数据写入主存
  • 写分配:将该数据所在的块读入 Cache 后,再讲数据写入 Cache

Cache容量:容量是越小越好好还是越大越好呢?

成本的角度考虑,我们希望Cache容量足够小,以至于可以降低存储器的价格。

性能的角度考虑,我们希望Cache可以足够大,如果所有数据都从速度较快的Cache中取得,就不需要从速度较慢的主存中获取,性能将会变好。

硬件方面考虑,Cache越大,寻址所需要的电路就会越多,受限于集成电路制造技术,大的Cache反而会比小的Cache稍慢。

总结

高速缓存存储器是现代计算机系统中不可或缺的重要组件,它通过提高数据访问速度,显著提升了计算机的整体性能。本文是高速缓存的入门知识,更深入的了解请关注后续更新。