轉譯後備緩衝區(translation lookaside buffer)
/ abbr. TLB, say "T-L-B" /
想像你整天都在一本厚電話簿裡查那幾個相同的電話號碼。每次翻書都很慢,於是你把最常用的號碼抄在電話旁的一張小便利貼上,先看那張。轉譯後備緩衝區正是記憶體的那張便利貼:一個極小、極快的硬體快取,記住最近用過的(頁號 → 頁框號)轉譯,使 CPU 通常根本不必去翻記憶體裡的分頁表。
更精確地說,TLB 是一個小巧、全相聯(或高度相聯)的硬體快取,通常只存幾十到幾百筆項目。每筆項目存著一個頁號連同它的頁框號。每次記憶體存取時,硬體把頁號送進 TLB,所有項目在單一週期內被「同時」比對(相聯搜尋)。若該頁在裡面——TLB 命中——頁框號直接吐出來,慢速的分頁表被略過。若不在——TLB 失誤——硬體(或作業系統)去走訪記憶體中的分頁表,取得頁框,並把該轉譯載入 TLB 以備下次之用,通常會逐出某個舊項目。由於真實程式會反覆碰觸相同的頁(區域性),一個小小的 TLB 就能攔下絕大多數的存取。
TLB 之重要,幾乎勝過分頁裡任何其他單一結構,因為沒有它,每次記憶體參考都得多付至少一次記憶體存取去讀分頁表——等於把記憶體延遲加倍。命中率一高,平均轉譯成本就趨近於零。誠實的提醒:TLB 是 CPU 每個行程環境的一部分,所以環境切換時必須處理(清空,或用位址空間識別碼加上標籤,否則某行程會讀到另一行程的轉譯);而它的小容量意味著區域性差、或工作集龐大且散布在許多頁上的程式,可能遭遇「TLB 顛簸」,失誤佔了主導——這正是大頁存在的原因之一。
某程式對位於頁 7 的一個小陣列迴圈一百萬次。第一次存取在 TLB 失誤,走訪分頁表得知頁 7 → 頁框 22,並把它存進 TLB。接下來的 999,999 次存取全部在 TLB 命中、瞬間取得頁框 22,再也不碰分頁表。
區域性讓小小的 TLB 划得來:一次失誤學會一個轉譯,接著湧入大量快速命中。
沒有 TLB,每筆經由記憶體分頁表的參考都至少要兩次記憶體存取。TLB 屬於每個行程的環境,所以環境切換時必須清空它或使用位址空間識別碼,否則某行程會讀到另一行程過時的轉譯。