Appearance
Cache 综合大题:映射+LRU+写策略一题打通
考情分析
Cache 大题最爱"一题串多点"。前面四篇分别讲了概念、映射、替换、写策略,本篇把它们拼成一道完整大题,按真题的设问节奏走一遍。
大纲定位
考纲第三章(六)「高速缓冲存储器(Cache)」四条的综合运用,并常与(七)虚拟存储器串在同一道大题里。
本篇不引入新知识点,只做跨小节的整合走查。
近年 Cache 大题真正长什么样
先说清楚各年考的到底是什么,别练错方向:
| 年份 | 实际考点组合 | 注意 |
|---|---|---|
| 2010-44 | 直接映射 + 地址算行号 + 命中率 + 局部性 | 题干明写「不考虑一致性维护位(脏位等)和替换算法控制位」——这道题不考写策略 |
| 2018-44 | 映射 + 虚存/TLB + 容量(含有效位、脏位、LRU 位) | |
| 2020-44 | 组相联 + LRU 位数 + 写策略 + 缺失次数统计 | |
| 2023-43 | C 循环 → 页数/缺页 + 局部性判定 + 虚实地址低位直通 | |
| 2025-43 | C 循环 → 块数(首址不对齐)+ 缺失率 + 平均访问时间 |
形态在变:早年的大题偏"给参数算字段",近三年(2020、2023、2025)清一色是给一段 C 代码,让你自己数块数、页数、访存次数。本篇下半部分的走查是前一种形态,做后一种形态的题还需要下面这几件事。
近年形态需要的几个额外动作
1. 从 C 语句数访存次数
- 只读(
x = a[i])或只写(a[i] = 0):1 次访存 - 读改写(
a[i] = a[i]/x):编译成 lw + sw,2 次访存
漏掉这一条,缺失率的分母会小一半,答案正好差 2 倍。
2. 数组占几个主存块——首址不对齐要多算一块
例:数组 8192 B、块大小 64 B。若首址块对齐,占
页数同理:
3. 局部性怎么判
数一个元素被访问几次:
4. 虚拟地址能不能直接切 Cache 组号
当 Cache 的 index + offset 位数
卷面上这句判据要明写出来,它本身就是给分点。
5. 平均访问时间
「缺失损失」是相对命中的额外开销,所以一次缺失的总代价是 命中时间
题目
某计算机主存地址 32 位、按字节编址。数据 Cache 大小 4 KB,2 路组相联,块大小 32 B,LRU 替换,写回 + 写分配策略,初始 Cache 为空。
- 写出主存地址划分(tag / 组号 / 块内偏移各多少位)
- 计算 Cache 的总存储容量(含全部开销位)
- 访问地址
0x00012C84,它落在哪一组?tag 是多少? - 程序依次访问同一组的三个主存块 A、B、C(顺序:读 A → 读 B → 写 A → 读 C → 写 B),统计命中情况与主存块传送次数
- 若改为写直达 + 非写分配,第 4 问的主存访问发生什么变化?
(1) 地址划分
- 块内偏移:块大小 32 B →
位 - 行数:4 KB ÷ 32 B = 128 行;组数:128 ÷ 2 路 = 64 组 → 组号
位 - tag:
位
(2) 总容量(含开销位)
每行需要的位:
| 项 | 位数 |
|---|---|
| 数据 | 32 B = 256 |
| tag | 21 |
| 有效位 | 1 |
| 脏位(写回策略才有) | 1 |
| LRU 位(2 路一组,每行 1 位够用) | 1 |
| 合计 | 280 |
总容量 =
两个小坑
脏位是写回策略才需要的——题目若给写直达,每行少 1 位。
LRU 位数写死一条规则:计数器法每行需
编者注(易错):8 路是 3 位(
),不是 8 位。真题考过 8 路的情形,且判分维度点名"必须用 解释"。别以为只会考 2 路。
有效位是干什么的:它标记这一行装没装过有效数据。判命中的完整条件是 有效位
(3) 具体地址走查
0x00012C84 展开成二进制(32 位):
0000 0000 0000 0001 0010 1100 1000 0100
└──────── tag(21) ────────┘└─组号(6)─┘└偏移(5)┘从低位往高位切:
- 块内偏移 = 低 5 位
00100= 4 - 组号 = 次 6 位
100100= 36 号组 - tag = 剩余高 21 位 =
0 0000 0000 0000 0010 0101= 0x25
检验:
(4) LRU + 写回的访问模拟
A、B、C 映射到同一组(2 路,即该组只有 2 个槽位)。逐次模拟,每行写出该组内容和脏位。
约定:下表每组内容按 最近使用(MRU)在左、最久未用(LRU)在右 排列,替换时淘汰右端。这个左右约定各家资料不一致,卷面上必须先声明再用。
| 访问 | 结果 | 组内变化 | 脏位/写回 |
|---|---|---|---|
| 读 A | 缺失,调入 A | [A] | A 干净 |
| 读 B | 缺失,调入 B | [B, A] | B 干净 |
| 写 A | 命中(写回策略:只写 Cache) | [A, B] | A 置脏 |
| 读 C | 缺失,替换 LRU = B(干净,直接丢弃) | [C, A] | |
| 写 B | 缺失(写分配:先调入 B),替换 LRU = A,A 是脏块要写回 | [B, C] | B 置脏,写回 A 一次 |
统计:
- 命中 1 次 / 访问 5 次,命中率 20%
- 主存块传送 = 调入 4 次(A、B、C、B)+ 脏块写回 1 次(A)= 5 次
最容易错的两处:第 3 次访问"写 A"在写回策略下不访问主存;最后替换 A 时必须先检查脏位——A 被写过,要先写回再腾位置。
(5) 换成写直达 + 非写分配
- 写 A(命中):写 Cache 的同时写主存 1 次(按字写)
- 写 B(缺失):非写分配——直接写主存,不调块,Cache 内容不变
- 读缺失仍要调块:A、B、C 共 3 次块调入
主存交互变成:3 次块调入 + 2 次字写。注意"块传送"和"字写入"开销不同(一个块 32 B),所以两种策略不能只比次数,真题通常会给出块传送时间和单字写时间让你算总开销——口径以题给为准。
答题套路
- 地址划分永远从低位往高位切:先偏移、再组号、剩下全是 tag
- 划完位数再写位区间——设问常是"各字段的位数及在物理地址中的位置",位置是独立判分维度:offset
、index 、tag - 总容量 = 行数 ×(数据位 + tag + 有效位 + 脏位 + 替换算法位),逐项列表不漏项
- 走查题先算字段值,再用"
"反向检验;也可用等价的 、 - 判命中要写四步:切字段 → 查第
组 → 逐路比有效位 + Tag → 写结论并写根因("Tag 匹配但有效位为 0,故不命中"/"Tag 为 105H ≠ 04CH,故不命中")。真题明确规定只答"不命中"不分析要扣分 - 模拟题逐次画组内容,每一步标 MRU/LRU 和脏位(左右约定先声明),替换时先看脏位决定要不要写回