Appearance
题目
假设某计算机按字节编址,Cache 有 4 个行,Cache 和主存之间交换的块大小为 1 个字(即 2 个字节)。若 Cache 的内容初始为空,采用 2 路组相联映射方式和 LRU 替换策略。访问的主存地址依次为 0, 4, 8, 2, 0, 6, 8, 6, 4, 8 时,命中 Cache 的次数是( )。
错因
A
漏读了"块大小 = 2 字节"——把字节地址直接当成块号,每个地址映射到不同的块。这样所有偶数地址(0, 4, 8, 2, 0, 6, 8, 6, 4, 8 全是偶数)的"块号"都是偶数,组号 = 块号 mod 2 全部为 0,全部到组 0。组 0 容量只有 2,10 次访问只能命中 1 次(第 8 次访问 6 时短暂复用)。
正确做法是先把字节地址折算成块号:块号 = 字节地址 / 2。
B
把 LRU 当成 FIFO(先进先出)算:在 step 9(访问 4,块号 2)时,按 FIFO 应淘汰最早进入的 6(在 step 6 进入),但按 LRU 应淘汰最近最少使用的 0(在 step 5 后未再使用)。两个策略在前几步看似一样,但中后段会出现差异,导致后续 step 10(访问 8)的命中状态不同。少算了 1 次命中得到 2。
D
多算了一次"伪命中"。常见路径:在 step 5(访问 0、块号 0)时,已经在 step 3 时把块 0 淘汰了,但学生没记住淘汰这一动作,误以为块 0 还在组 0 里,把它判成了 HIT。这种"忘记淘汰"是 LRU 模拟里最容易踩的坑——必须每一步写出当前组内容,不能心算。
总解析
第一步:算出 Cache 的组织
- Cache 共 4 行,2 路组相联 → 2 组,每组 2 行
- 块大小 = 1 字 = 2 字节
- 按字节编址 → 块号 = 字节地址 / 2
- 组号 = 块号 mod 2
| 字节地址 | 块号 (addr/2) | 组号 (块号 mod 2) |
|---|---|---|
| 0 | 0 | 0 |
| 4 | 2 | 0 |
| 8 | 4 | 0 |
| 2 | 1 | 1 |
| 0 | 0 | 0 |
| 6 | 3 | 1 |
| 8 | 4 | 0 |
| 6 | 3 | 1 |
| 4 | 2 | 0 |
| 8 | 4 | 0 |
第二步:分组逐步模拟
每组 2 槽,LRU 队列约定:左为最久未用(LRU),右为最近使用(MRU)。
| step | 地址 | 块 | 组 | 命中? | 组 0(LRU→MRU) | 组 1 |
|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 0 | M | [0] | [ ] |
| 2 | 4 | 2 | 0 | M | [0, 2] | [ ] |
| 3 | 8 | 4 | 0 | M(淘汰 0) | [2, 4] | [ ] |
| 4 | 2 | 1 | 1 | M | [2, 4] | [1] |
| 5 | 0 | 0 | 0 | M(淘汰 2) | [4, 0] | [1] |
| 6 | 6 | 3 | 1 | M | [4, 0] | [1, 3] |
| 7 | 8 | 4 | 0 | H | [0, 4] | [1, 3] |
| 8 | 6 | 3 | 1 | H | [0, 4] | [1, 3] |
| 9 | 4 | 2 | 0 | M(淘汰 0) | [4, 2] | [1, 3] |
| 10 | 8 | 4 | 0 | H | [2, 4] | [1, 3] |
第三步:数命中次数
命中发生在 step 7、8、10——共 3 次。
最终答案是 C(3)。
关键判定要点:
- 先把"地址"换成"块号"再做映射 —— 块大小不为 1 时永远要做这步,本题的 1 字 = 2 字节就是典型陷阱
- 组相联的组号 = 块号 mod 组数(不是块号 mod 行数)—— 别把"4 行"误用作组数
- LRU 模拟必须显式写出每组的当前内容——心算两步以上几乎必错;表格化推演是最稳的做法
- HIT 也要更新 LRU 状态(命中的块变成 MRU),不止 MISS 时才动队列