最近最少使用置換(LRU replacement)
/ L-R-U /
既然我們無法像最佳法那樣看見未來,次好的辦法就是賭未來長得像最近的過去。如果一個頁很久沒被碰過,它大概已不在程式目前的焦點中,很可能會繼續不被使用;而你片刻前用過的頁,你大概很快又會用到。LRU 置換下的正是這個賭注:當它必須逐出時,移走最近最少使用的頁——也就是最久沒有被參考過的那一個。
把 LRU 想成是「往後看」的最佳法,只不過方向相反。最佳法逐出未來最久才用到的頁;LRU 逐出過去最久前用過的頁。要做到這點,它必須記住各頁最後被存取的先後順序。兩種教科書做法:用計數器——每次存取就為該頁蓋上一個邏輯時鐘的戳記,逐出戳記最小的;或用堆疊——每次存取就把該頁移到一個雙向鏈結串列的頂端,於是底端永遠是 LRU 犧牲者。因為程式確實展現區域性,這個「以過去為序幕」的賭注在實務上運作得很好,LRU 在典型工作負載上接近最佳法。
為什麼重要,以及它誠實的難處:LRU 是堆疊演算法,所以不像 FIFO,它絕不會遭遇貝雷迪異常——更多頁框永遠不會讓它變糟。但精確的 LRU 很昂貴:它需要硬體在每一次記憶體參考時更新一個時間戳或重排一個串列,這在現實中代價太高。所以實際系統並不跑真正的 LRU;它們跑的是它的廉價近似——參考位元老化法與第二次機會(時鐘)演算法——以一小部分的成本,捕捉到 LRU 大部分的好處。
頁框 = 3 裝著 A、B、C;目前的存取順序是 C(最舊)、A、B(最近)。對 D 的錯誤迫使逐出:LRU 移走 C,也就是最近最少使用的,得到頁框 A、B、D。若接著參考 A,它就變成最近的,原本 C 那種老舊的位置現在輪到 B。
逐出閒置最久的頁——新近程度是 LRU 用來替代無法得知的未來的替身。
精確的 LRU 很少被實作,因為在每次記憶體存取時追蹤最後使用順序需要昂貴的硬體;真實系統使用近似法(老化、第二次機會),表現得像 LRU 卻不必逐次記帳。LRU 本身也只是最佳法的近似,並不等於最佳法。