page table 解決了虛擬位址到實體位址的對應問題,但它也帶來一個效能問題。每次 CPU 存取記憶體,如果都要走多層 page table,成本會非常高。一次普通的 load/store 可能變成好幾次額外的記憶體讀取。為了避免這件事,CPU 會使用 TLB,也就是 Translation Lookaside Buffer。
TLB 可以想成位址轉換結果的快取。當 CPU 最近查過某個虛擬頁面對應到哪個實體頁面,下次再碰到同一個虛擬頁面時,就可以直接從 TLB 拿結果,不必重新走 page table。對 CPU 來說,TLB hit 很快;TLB miss 則需要重新查 page table,甚至可能進一步觸發 page fault。
這也是為什麼記憶體存取模式會影響效能。如果程式一直在一小段記憶體範圍內工作,TLB 命中率通常會比較好。如果工作集很大、跳來跳去存取很多不同頁面,TLB miss 可能變多,即使資料都在 RAM 裡,效能還是會下降。
context switch 也會牽涉 TLB。不同 process 有不同的 page table,同一個虛擬位址在不同 process 裡可能指向不同實體頁面。CPU 切換到另一個 process 時,不能把舊 process 的轉換結果拿來亂用。早期做法常需要 flush TLB,後來硬體有 ASID 或 PCID 這類機制,可以幫助區分不同 address space,減少 flush 的成本。
TLB 還和 huge page 有關。一般 4 KiB page 如果要覆蓋很大的記憶體範圍,需要很多 TLB entry。Huge page 用比較大的 page size,例如 2 MiB,可以讓一筆 TLB entry 覆蓋更多記憶體,降低 TLB 壓力。不過 huge page 也有配置、碎片和延遲等代價,所以不是永遠打開就一定比較好。
在 production 上,TLB 問題不一定是第一個會看的方向,但它能解釋一些「資料都在記憶體裡,為什麼還是慢」的情況。尤其是大型資料庫、虛擬化、HPC 或大量 random access 的 workload,TLB 行為可能會變成重要因素。
下一篇開始看 page fault。當 TLB 和 page table 都無法給出有效轉換時,CPU 會把問題交給 kernel。page fault 是理解 demand paging、COW 和 segmentation fault 的關鍵入口。