精简版 · 小杯2026-08 冻结,已停止更新(发布前修订了 4 处已知错误)。后续勘误与新增内容只在正式版。看正式版(中杯)→
Skip to content

Cache 综合大题:映射+LRU+写策略一题打通

考情分析

Cache 大题最爱"一题串多点"。前面四篇分别讲了概念、映射、替换、写策略,本篇把它们拼成一道完整大题,按真题的设问节奏走一遍。

大纲定位

考纲第三章(六)「高速缓冲存储器(Cache)」四条的综合运用,并常与(七)虚拟存储器串在同一道大题里。

本篇不引入新知识点,只做跨小节的整合走查。

近年 Cache 大题真正长什么样

先说清楚各年考的到底是什么,别练错方向:

年份实际考点组合注意
2010-44直接映射 + 地址算行号 + 命中率 + 局部性题干明写「不考虑一致性维护位(脏位等)和替换算法控制位」——这道题不考写策略
2018-44映射 + 虚存/TLB + 容量(含有效位、脏位、LRU 位)
2020-44组相联 + LRU 位数 + 写策略 + 缺失次数统计
2023-43C 循环 → 页数/缺页 + 局部性判定 + 虚实地址低位直通
2025-43C 循环 → 块数(首址不对齐)+ 缺失率 + 平均访问时间

形态在变:早年的大题偏"给参数算字段",近三年(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。若首址块对齐,占 8192/64=128 块;若首址的低 6 位是 32(不对齐),首尾各占半块,实际占 129 块。真题就是靠这一块之差区分考生。

页数同理:(页内偏移+总长)/页大小

3. 局部性怎么判

数一个元素被访问几次:2 才有时间局部性;相邻地址是否顺序访问,决定空间局部性。两者分开判、分开写理由,只答"局部性差"不给分。

4. 虚拟地址能不能直接切 Cache 组号

Cache 的 index + offset 位数 页内偏移位数时,这几位在虚实地址中完全相同(翻译只换高位),可以直接从虚拟地址切出组号和块内偏移,不必等 TLB。但 Tag 必须来自物理地址

判据log2(组数)+log2(块大小)log2(页大小)

卷面上这句判据要明写出来,它本身就是给分点。

5. 平均访问时间

AMAT=命中时间+缺失率×缺失损失

「缺失损失」是相对命中的额外开销,所以一次缺失的总代价是 命中时间 + 缺失损失。别默认套"同时访问"模型。

题目

某计算机主存地址 32 位、按字节编址。数据 Cache 大小 4 KB,2 路组相联,块大小 32 B,LRU 替换,写回 + 写分配策略,初始 Cache 为空。

  1. 写出主存地址划分(tag / 组号 / 块内偏移各多少位)
  2. 计算 Cache 的总存储容量(含全部开销位)
  3. 访问地址 0x00012C84,它落在哪一组?tag 是多少?
  4. 程序依次访问同一组的三个主存块 A、B、C(顺序:读 A → 读 B → 写 A → 读 C → 写 B),统计命中情况与主存块传送次数
  5. 若改为写直达 + 非写分配,第 4 问的主存访问发生什么变化?

(1) 地址划分

  • 块内偏移:块大小 32 B → log232=5
  • 行数:4 KB ÷ 32 B = 128 行;组数:128 ÷ 2 路 = 64 组 → 组号 log264=6
  • tag:3265=21
tag21 | 6 | 5

(2) 总容量(含开销位)

每行需要的位:

位数
数据32 B = 256
tag21
有效位1
脏位(写回策略才有)1
LRU 位(2 路一组,每行 1 位够用)1
合计280

总容量 = 128×280=35840 位 = 4480 B(数据 4096 B + 开销 384 B,开销约 9.4%)。

两个小坑

脏位是写回策略才需要的——题目若给写直达,每行少 1 位。

LRU 位数写死一条规则:计数器法每行需 log2(路数) 位。

2 1 ,4 2 ,8 3 

编者注(易错):8 路是 3 位(log28),不是 8 位。真题考过 8 路的情形,且判分维度点名"必须用 log28 解释"。别以为只会考 2 路。

有效位是干什么的:它标记这一行装没装过有效数据。判命中的完整条件是 有效位 =1 且 Tag 匹配——两个缺一不可。真题考过这样一问:Tag 恰好匹配但有效位为 0,结论是不命中(防的是上电后的随机残留)。

(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

检验:地址=(0x25×64+36)×32+4=(37×64+36)×32+4=2404×32+4=76932=0x12C84

(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),所以两种策略不能只比次数,真题通常会给出块传送时间和单字写时间让你算总开销——口径以题给为准。

答题套路

  1. 地址划分永远从低位往高位切:先偏移、再组号、剩下全是 tag
  2. 划完位数再写位区间——设问常是"各字段的位数及在物理地址中的位置",位置是独立判分维度:offset =[b1:0]、index =[b+s1:b]、tag =[m1:b+s]
  3. 总容量 = 行数 ×(数据位 + tag + 有效位 + 脏位 + 替换算法位),逐项列表不漏项
  4. 走查题先算字段值,再用"(tag×+)×+"反向检验;也可用等价的 块号=地址/块大小组号=块号mod组数
  5. 判命中要写四步:切字段 → 查第 X 组 → 逐路比有效位 + Tag → 写结论并写根因("Tag 匹配但有效位为 0,故不命中"/"Tag 为 105H ≠ 04CH,故不命中")。真题明确规定只答"不命中"不分析要扣分
  6. 模拟题逐次画组内容,每一步标 MRU/LRU 和脏位(左右约定先声明),替换时先看脏位决定要不要写回

真题练习