Cache 的映射方式决定了主存(Main Memory)中的数据块如何放置到 Cache 中。这本质上是在硬件复杂度、访问速度和空间利用率之间寻找平衡。业界主要存在以下三种经典的映射方式:
- 直接映射 (Direct Mapping)
* 映射规则:主存中的每一个数据块,只能映射到 Cache 中唯一的一个固定行(Line)。
* 计算公式:Cache行号 = 主存块号 % Cache总行数
* 硬件结构:Tag(标记)+ Data(数据)。由于每个主存块只能去一个固定的 Cache 行,因此不需要比较器阵列,只需将地址中的 Tag 字段与当前 Cache 行的 Tag 进行单次比较即可。
* 优点:硬件实现最简单,查找速度最快(只需一次比较),成本最低。
* 缺点:冲突率极高。如果程序频繁交替访问两个映射到同一 Cache 行的主存块,会导致 Cache 行被不断替换(Thrashing/抖动),命中率急剧下降。
- 全相联映射 (Fully Associative Mapping)
* 映射规则:主存中的任何一个数据块,可以放入 Cache 中的任意一个空闲行。
* 硬件结构:Tag + Data。因为数据可以放在任何位置,所以查找时必须将输入地址的 Tag 与 Cache 中所有行的 Tag 同时进行并行比较。
* 优点:极其灵活,完全没有位置冲突,Cache 的空间利用率最高,理论命中率最高。
* 缺点:硬件成本极高。需要大量的比较器(Cache 越大,比较器越多),且并行比较带来的功耗和延迟极大,因此无法做大,通常只用于容量极小的 Cache(如 TLB 或极小的 L1 Cache)。
- 组相联映射 (Set Associative Mapping)
* 映射规则:这是前两者的折中与结合。Cache 被分为若干个组 (Set),每个组包含 N 个行(称为 N 路组相联,N-way)。主存块首先通过取模运算映射到唯一的组,然后可以放入该组内的任意一行。
* 计算公式:组号 = 主存块号 % Cache总组数
* 硬件结构:Tag + Data。查找时,先定位到具体的组,然后在该组内部的 N 个行中进行并行比较。
* 优点:完美平衡了速度、成本和命中率。既避免了直接映射的严重冲突,又避免了全相联映射的巨大硬件开销。
* 缺点:硬件复杂度介于两者之间,随着路数(N)的增加,访问延迟也会随之增加。
💡 核心总结与工程实践
在实际的现代计算机体系结构中,组相联映射 (Set Associative) 是绝对的主流:
* L1 Cache:为了追求极致速度,通常采用低路数的组相联(如 4-way 或 8-way),甚至部分采用直接映射。
* L2/L3 Cache:容量较大,对速度要求相对 L1 稍低,通常采用高路数的组相联(如 16-way、20-way 甚至更高),以最大化命中率。
* TLB (页表缓存):因为页表项数量少且访问极其频繁,通常采用全相联映射或高路数组相联。
要不要我接着讲讲 Cache 的写策略?比如写回(Write-back)和直写(Write-through)的区别和适用场景。