記憶體階層與快取

寫回(write-back)

想像你正在編輯一份借來的文件。你可以每改一句就跑去原始檔案庫重新歸檔(安全,但累人),或者把所有編輯都在桌上的副本上做完,等你終於用完它時才把整份歸檔一次。寫回就是快取那種偷懶卻高效的第二種做法:當 CPU 寫資料時,改動只發生在快取裡,下方較慢的記憶體稍後才更新——只在那條列終於被淘汰時。

為了讓這行得通,每條快取列帶一個髒位元。當 CPU 寫入某條列,快取更新自己的副本並把髒位元設為 1,標記「這條列有記憶體尚不知道的改動」。這條列可以被寫又寫許多次,全以快取的快速度進行,記憶體完全不被碰。只有當這條列必須被淘汰(為進來的區塊騰位)時,快取才檢查髒位元:若被設起,就在重用槽位前把整條列寫回記憶體;若是乾淨的,就直接丟棄這條列,因為記憶體已持有一模一樣的副本。

寫回的大勝在於流量:迴圈裡更新一千次的變數,到最後只碰一次慢記憶體,而非一千次。這使它成為幾乎所有現代快取的預設。代價是誠實的:快取與記憶體暫時不一致(在寫回發生前,記憶體持有過時的值),這讓任何獨立讀記憶體的東西變複雜——DMA 裝置、其他核心、快取一致性協定都必須考慮髒的快取副本。它的硬體也略複雜(髒位元、淘汰時的寫回路徑),且淘汰一條髒列要多花成本,因為必須執行那次延後的寫入。另一條路——寫穿——則用這份效率換取簡單與永遠一致的記憶體。

一個迴圈在裝著 total 的快取列上做 1000 次「total += a[i]」。寫回每次迭代只更新快取副本(髒位元設起),到最後列被淘汰時才把最終值寫進記憶體一次——1 次記憶體寫入,而非 1000 次。

寫入只命中快取;一條髒列只在淘汰時被刷回記憶體一次。

採寫回時,記憶體在淘汰前可能持有「過時」的值。這對單一核心的正確性無妨,但任何直接讀記憶體的東西——DMA、其他核心——都必須被告知有髒的快取副本;這正是快取一致性協定存在的一大原因。

又称
copy-back回寫