首页/计算机组成原理/存储器/Cache映射方式 🔗 在 Obsidian 中打开
计算机组成原理 · 存储器

Cache映射方式

重要度 ⭐⭐⭐⭐⭐存储器层次结构直接映射全相联组相联命中率存储器
速查
映射方式决定主存块如何放置到 Cache:直接映射每块只能去固定行(行号 = 块号 mod 行数);全相联可去任意行(冲突最低、硬件最贵);组相联折中(组号 = 块号 mod 组数,组内任选路)。

速查

映射方式主存块可放置位置
直接映射只能映射到固定 Cache 行
全相联可映射到任意 Cache 行
组相联折中:n 路组相联,每组 n 行

概述

Cache 是位于 CPU 和主存之间的高速小容量存储器,利用程序访问的局部性原理来减少 CPU 访问主存的次数。映射方式决定了主存块如何放置到 Cache 中,是后续地址划分、命中率计算与替换算法的基础。

Cache 基本概念

Cache 行(Cache Line / Block)

  • Cache 与主存之间数据交换的最小单位
  • 通常包含多个字节(如 64 字节)

地址划分

主存地址 = [标记 Tag][组号/行号][块内偏移 Offset]

命中率

命中率 $h = \frac{\text{Cache命中次数}}{\text{总访问次数}}$,缺失率 $= 1 - h$,平均访问时间 $= h \times T_{cache} + (1-h) \times T_{main}$。

直接映射(Direct Mapped)

映射规则

Cache 行号 = 主存块号 mod Cache 行数

每个主存块只能映射到 Cache 的固定位置

地址结构

| Tag | 行号(Index) | 块内偏移(Offset) |

示例

主存 8 块,Cache 4 行,直接映射:
主存块 0 → Cache 行 0
主存块 1 → Cache 行 1
主存块 2 → Cache 行 2
主存块 3 → Cache 行 3
主存块 4 → Cache 行 0  ← 与块 0 冲突
主存块 5 → Cache 行 1  ← 与块 1 冲突
主存块 6 → Cache 行 2
主存块 7 → Cache 行 3

特点

  • 优点:实现简单,查找速度快(只需比较一个 Tag)
  • 缺点:冲突率高,多个主存块竞争同一 Cache 行
  • 适用:L1 Cache(追求速度)

查找过程

  1. 用 Index 定位 Cache 行
  2. 比较 Tag 是否匹配
  3. 检查有效位
  4. 命中 → 用 Offset 取数据
  5. 未命中 → 从主存取块

全相联映射(Fully Associative)

映射规则

主存块可以放入 Cache 的任意一行

地址结构

| Tag(整个主存块号) | 块内偏移(Offset) |

特点

  • 优点:冲突率最低,空间利用率最高
  • 缺点:需要比较所有行的 Tag,硬件成本高
  • 适用:小容量 Cache(如 TLB)

查找过程

  1. 并行比较所有 Cache 行的 Tag
  2. 任一行匹配且有效 → 命中
  3. 未命中 → 需要替换策略决定替换哪行

硬件实现

Tag 比较器数量 = Cache 行数
每个比较器比较 Tag 位数的位
→ 硬件成本随 Cache 行数线性增长

组相联映射(Set Associative)⭐

映射规则

Cache 分为若干组(Set),每组包含若干路(Way)
组号 = 主存块号 mod 组数
主存块映射到固定组,但在组内可以放在任意路

地址结构

| Tag | 组号(Set Index) | 块内偏移(Offset) |

示例:2 路组相联,Cache 4 行 = 2 组

组 0(路 0 和路 1):主存块号 % 2 = 0 的块
组 1(路 0 和路 1):主存块号 % 2 = 1 的块

主存块 0 → 组 0(可放路 0 或路 1)
主存块 2 → 组 0(可放路 0 或路 1)
主存块 4 → 组 0(与块 0 或块 2 冲突)
主存块 1 → 组 1
主存块 3 → 组 1

常见配置

2 路组相联:每组 2 行
4 路组相联:每组 4 行
8 路组相联:每组 8 行
n 路组相联:每组 n 行

特点

  • 折中方案:冲突率低于直接映射,硬件复杂度低于全相联
  • n 路组相联需要 n 个比较器(而非全部行数)
  • L2 / L3 Cache 常用(如 8 路或 16 路组相联)

命名规范

n-way set-associative Cache with m sets:
- 总行数 = n × m
- 每个地址映射到 n 个可能位置(n 路组相联,组内 n 路任选)

三种映射方式对比

考查重点比较器数量、冲突率与典型应用是选择题常客;组相联的"路数"等于每组行数。
特性直接映射全相联组相联
映射位置唯一任意组内任意
比较器数1行数路数
冲突率
硬件成本
速度最快较快
典型应用L1 CacheTLBL2/L3 Cache

Cache 容量计算

公式

  • Cache 容量(数据容量)= 行数 $\times$ 块大小
  • Cache 总存储位数 = 行数 $\times$ (有效位 + Tag 位 + 数据位)

示例

直接映射 Cache:256 行,数据块 32B,地址 32 位
Offset = log₂(32) = 5 位
Index  = log₂(256) = 8 位
Tag    = 32 - 8 - 5 = 19 位
每行   = 1(有效位) + 19(Tag) + 32×8(数据) = 276 位
总存储位数 = 256 × 276 = 70656 位 ≈ 8.6KB
Cache 容量(纯数据)= 256 × 32B = 8KB

Cache 缺失(Miss)类型 · 3C 模型

  1. Compulsory Miss(冷启动缺失):首次访问某块
  2. Capacity Miss(容量缺失):Cache 太小,工作集放不下
  3. Conflict Miss(冲突缺失):映射冲突导致频繁替换
3C 的解决方法
  • 冷启动:预取(Prefetching)
  • 容量:增大 Cache
  • 冲突:增加相联度

地址映射例题

主存 1MB,Cache 8KB,块大小 64B,直接映射
地址 20 位(1MB = 2²⁰,故地址为 20 位)

Offset = log₂(64) = 6 位
Index  = log₂(8KB/64B) = log₂(128) = 7 位
Tag    = 20 - 7 - 6 = 7 位

主存地址 0x03A7C = 0000 0011 1010 0111 1100(20 位)
Tag(7位)   = 0000001 (1)
Index(7位) = 1101001 (105)
Offset(6位)= 111100  (60)
→ 查 Cache 第 105 行,比较 Tag=1,偏移 60 字节

易错点

必记
  1. 直接映射用 Index 定位,只需 1 个比较器
  2. 全相联用整个块号做 Tag,需要所有行并行比较
  3. 组相联的"n 路"是每组 n 行,不是 n 组
  4. Cache 容量不包括 Tag 和有效位的开销(数据容量 = 行数 $\times$ 块大小)
  5. 有效位必须检查,无效行即使 Tag 匹配也不算命中
  6. 组相联 n 路需要n 个比较器,不是组数个
  7. 地址位划分:$Tag + Index + Offset =$ 总地址位数

记忆卡片

直接映射的映射公式?
Cache 行号 = 主存块号 mod Cache 行数。
组相联的"n 路"指什么?
每组 n 行,不是 n 组;需要 n 个比较器。
三种方式比较器数分别是多少?
直接=1,全相联=行数,组相联=路数。
Cache 容量算不算 Tag 位?
数据容量不算;总存储位数才含 Tag+有效位。
3C 缺失是哪三种?
冷启动 / 容量 / 冲突(Compulsory/Capacity/Conflict)。
L2/L3 常用哪种映射?
组相联(如 8 路或 16 路)。

交互动画 · 主存块 → Cache 行映射

主存块 Cache 行 块 0 块 1 块 2 块 3 块 4 块 5 块 6 块 7 行 0 行 1 行 2 行 3
点击左侧主存块,查看它在当前映射方式下可放入哪些 Cache 行
当前:直接映射
橙色流动虚线表示映射路径:直接映射每块只去 1 行;2 路组相联每块去固定组内的 2 行;全相联可去任意行。
地址位划分随映射方式而变
第 0/8 步
点击 播放 逐步访问 块 0 1 4 5 0 4 0 5:分解地址 → 定位行 → 比较 Tag → 命中/装入/淘汰
当前:直接映射(命中 0 / 缺页 0)

相关知识点

cache-replacement-and-write cache-memory virtual-memory

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。