分頁與位址轉換

分頁表(page table)

一本書的索引是最貼切的畫面。你想找「光合作用」那一節,但你不會把每一頁都翻過去;你在索引裡查「光合作用」,它告訴你「第 214 頁」。分頁表就是記憶體的那份索引。程式說出一個頁(「主題」),分頁表就告訴硬體哪一個實體頁框(「真正的頁碼」)裝著它。一次查找,就把邏輯名稱變成實體位置。

精確地說,分頁表是每個行程各自的一種資料結構,該行程位址空間裡每一頁對應一筆項目。第 p 號項目存著目前裝著頁 p 的頁框號(外加一些控制位元,詳見分頁表項目)。要翻譯一個邏輯位址,硬體把它拆成(頁號 p, 偏移 d),用 p 當作「索引」去讀分頁表,取出頁框號 f,再把實體位址組成「頁框 f, 偏移 d」。由於每個行程都有自己的分頁表,兩個行程裡相同的頁號可以對應到兩個不同的頁框,這正是行程之間即便共用同一塊實體 RAM 也能彼此隔離的方法。當前行程分頁表的位址本身則存在一個硬體暫存器裡,好讓 CPU 知道該去哪查。

分頁表之所以重要,是因為它「就是」讓分頁得以運作的那張地圖:沒有它,散落各處的頁框便無從使用。誠實的麻煩在於大小與速度。分頁表可能很大——4 KB 頁的 32 位元位址空間有 2^20(約一百萬)頁,因此約一百萬筆項目,而 64 位元空間更是天文數字般龐大——所以表本身住在主記憶體裡,而非暫存器裡。又因它住在記憶體裡,最天真的設計會需要一次記憶體存取去讀分頁表、再加一次去讀真正的資料,把每次記憶體參考的代價「加倍」。這個問題正是轉譯後備緩衝區(TLB)以及各種巧妙的表結構(多層、雜湊、反轉)存在的目的。

某行程的分頁表為〔頁 0 → 頁框 9、頁 1 → 頁框 2、頁 2 → 頁框 17、頁 3 → 頁框 5〕,則頁 2、偏移 100 的邏輯位址,藉由讀取第 2 號項目(頁框 17)並組成「頁框 17, 偏移 100」來翻譯。若頁框為 4 KB,即實體位元組 17 * 4096 + 100 = 69732。

分頁表以頁號為索引;讀一筆項目得到頁框,再把偏移接上去。

分頁表是每個行程各自一份、住在主記憶體裡,這正是為何天真的查找會讓每次記憶體存取加倍——TLB 的存在就是為了避開這點。頁號是直接拿來索引這張表的,並非用搜尋的。

又称
page map頁表頁面表