“A中先写块0,再读块4,再读块8。若LRU选择块0为victim,必须先按写策略保存脏数据。增加相联度不会自动解决写回正确性;替换了tag却漏写旧dirty块,后面重新读块0会丢失之前的写入。”
形式陈述
对缓存块,写策略至少有两个独立选择。Write-through(WT)在写命中时更新缓存并把这次写送到下层;write-back(WB)先只改缓存,把该块标dirty,逐出或显式flush时再把最新块写回。
写缺失时,write-allocate(WA)先取得该块,再在缓存内修改;no-write-allocate(NWA)把写送往下层而不在本层分配该块。本文对WA先取完整块,保留未写字节;不使用整块覆盖优化。WB/WT与WA/NWA是两个轴,常见组合不等于唯一合法组合。
dirty表示“当前缓存副本相对于下层需要回写”,不是“值非零”,也不是“最近访问过”。有效dirty块被替换前,必须用旧tag和index重建旧块地址并保存数据;然后才能覆盖tag与数据。
直觉
WB合并同一块上的多次小写,减少向下层传送的次数;代价是最新值可能暂时只在缓存里。WT更早传播每次写,但下层接收、写缓冲排空和掉电保存依然是不同事件。
写缺失是否分配决定“要不要把这个对象带进缓存”。若只是一次流式写,带入整块可能没有复用;若稍后立即读回,分配又可能有利。这里没有不依赖工作负载的万能组合。
例子与边界
同一串写,三份传输账单
取单行缓存、B=8,初始内存全零,依次执行 W04=9; W04=10; R04; R20,均为四字节访问。用需求传输计费、结束时不额外flush:
| 策略 | 填入整块 | 向下层word写 | 脏块回写 | 说明 |
|---|---|---|---|---|
| WB+WA | 2 | 0 | 1 | 两写合并,R20逐出含10的块0 |
| WT+WA | 2 | 2 | 0 | 两次写均下传,之后逐出干净块 |
| WT+NWA | 2 | 2 | 0 | 两写都不分配;R04才填块0,R20再填块4 |
最后两种总传输数在此例恰相同,命中轨迹不同:WT+WA的第二写和R04命中,WT+NWA的两个写都缺失,R04也缺失。不能由一个总数反推出策略。
写半块必须保留另一半
块0的前四字节原来组成7,后四字节原来组成8。对0x04写9后,块应为 (7,9)。若WA只把写入word放入一块未初始化缓冲,未来回写整块就可能破坏前面的7;“本次只写四字节”不能为其余字节丢失开脱。
程序结束不自动等于flush
共同终点任务的两路配置结束时,块0x08仍dirty,缓存中word为13而下层仍为0。需求访问已经给出正确读值,但若题目另要求把所有修改送到下层,必须追加一次回写。直接映射配置在需求过程中已经逐出了这个块,所以没有同样的追加动作。
推论与应用
flush到某一缓存下层不等于数据已跨过断电保护边界。WAL讨论日志与数据页的恢复先后,也不能替CPU缓存自动提供持久化保证。这里的下层可仍是易失的另一层cache或DRAM。
多核下,dirty还必须与缓存一致性的写权限协调:不能让两份私有脏副本同时自称最新。WB解决何时传播数据,一致性协议解决谁有资格读写和谁负责提供最新数据。
参考资料
- UC Berkeley CS61C,Direct Mapped Cache 与 Fully Associative Cache,课程笔记,访问于 2026-10-08。
- John L. Hennessy and David A. Patterson, Computer Architecture: A Quantitative Approach, 6th ed., 2017,Appendix B。本文传输数量以明示的word写与整块搬运分别计费。