Appearance
题目
假定主存地址位数为 32 位,按字节编址,主存和 Cache 之间采用直接映射方式,主存块大小为 4 个字,每字 32 位,写操作时采用回写 (Write Back) 方式,则能存放 4K 字数据的 Cache 的总容量的位数至少是( )。
错因
A
只算了 Tag + 数据,漏掉了有效位 (valid) 和脏位 (dirty)。每行 18 + 128 = 146 位,乘以 1024 行 = 146K 位。少算 2 位/行:
- 漏 valid → 无法判断该 Cache 行是否含有效内容(开机时 Cache 里都是垃圾,必须靠 valid 区分)
- 漏 dirty → 回写法的核心标志:被替换出去时不知道要不要写回主存,回写就退化了
B
只漏掉了一位——多半是漏了 dirty 位(18 + 1 valid + 128 data = 147)。常见误区:"只有写时才用 dirty,要等到具体写操作时再加"——实际上 dirty 位是 Cache 行的结构性元数据,每行永久占一位。回写法 ≡ 每行 +1 dirty 位,写不写入是这一位的状态变化,但位本身是固定开销。
D
多算了 10 位/行:18 + 10 + 1 + 1 + 128 = 158。错答的人误把"行号"也存进 Cache 行里——直接映射下行号是用主存地址的中段位索引到具体行的,行号本身是地址的一部分,不需要再存。Cache 只需要存"主存地址中除了行号和块内偏移之外"的高位部分,那才是 Tag。
总解析
核心思路:Cache 总容量 = 行数 × 每行所需位数 = 。关键是把每一项位数算对、不漏不多。
第一步:拆解主存地址
主存地址 32 位,按字节编址,每行存放 1 个主存块。
- 块大小 = 4 字 × (32 位/字) ÷ 8 = 16 字节 = B → 块内偏移 4 位
- Cache 数据容量 = 4K 字 = 4K × 4 B = 16 KB
- Cache 行数 = 16 KB ÷ 16 B = = 1024 行 → 索引(行号) 10 位
- Tag 位数 = 32 − 10 − 4 = 18 位
第二步:算每行的位数
Cache 一行的"账本":
| 字段 | 位数 | 说明 |
|---|---|---|
| Tag(标记) | 18 | 用于和 CPU 来访地址的高 18 位比对,命中判定的依据 |
| Valid(有效位) | 1 | 区分这一行是真实数据还是上电后的垃圾 |
| Dirty(脏位) | 1 | 回写法专用:被改过 → 替换时要写回主存;未改过 → 直接覆盖 |
| Data(数据) | 16 字节 × 8 = 128 | 实际缓存的主存块 |
| 合计 | 148 | 每行 148 位 |
第三步:算总容量
第四步:核对各选项的差距来源
| 选项 | 每行位数 | 漏算/多算 |
|---|---|---|
| A. 146K | 146 = 18 + 128 | 漏 valid + dirty |
| B. 147K | 147 = 18 + 1 + 128 | 漏 dirty(或漏 valid) |
| C. 148K | 148 = 18 + 1 + 1 + 128 | 正确 ✓ |
| D. 158K | 158 = 18 + 10 + 1 + 1 + 128 | 多存了行号(10 位) |
最终答案是 C(148K 位)。
易错点速记:
- valid 和 dirty 是结构性元数据,每行各占 1 位永久存在,不是按需出现
- 回写法 ↔ dirty 位:见到"回写"就要加 dirty;如果是"全写法(write through)"则不需要 dirty 位
- 行号不存进 Cache:行号是用地址索引出来的,存了就重复了;只有 Tag 才需要存
- 题目说"按字节编址"——块内偏移按字节算(4 位),不要按字算成 2 位