分頁表（page table）是一種資料結構，它用於計算機作業系統中的虛擬記憶體系統，其儲存了虛擬地址到物理地址間的對映。虛擬地址在訪問程序中是唯一的，而物理地址在硬體（比如記憶體）中是唯一的。 分頁表的角色 在作業系統中使用虛擬記憶體，每個程序會認為使用一塊大的連續的記憶體。事實上，每個程序的記憶體散佈在物理記憶體的不同區域。或者可能被調出到備份儲存中 一般在硬碟。當一個程序請求自己的記憶體，作業系統負責把程式生成的虛擬地址，對映到實際儲存的物理記憶體上。作業系統在分頁表中儲存虛擬地址到物理地址的對映。每個對映被稱為分頁表項（page table entry，PTE）。 轉換過程 CPU 的記憶體管理單元（memory management unit MMU）儲存最近用過的對映快取，來自作業系統分頁表。被稱為轉譯後備緩衝區（translation lookaside buffer TLB）。TLB 是一個索引快取。 當需要將虛擬地址轉換為物理地址時，首先搜尋 TLB。如果找到匹配（TLB 命中），則返回物理地址並繼續儲存器訪問。然而，如果沒有匹配（稱為 TLB 未命中），則儲存器管理單元或作業系統 TLB 未命中處理器通常會查詢頁表中的地址對映以檢視是否存在對映（頁面遍歷）。如果存在，則將其寫回 TLB（這必須完成，因為硬體透過虛擬儲存器系統中的 TLB 訪問儲存器），並且重啟錯誤指令（這也可以並行發生）。此後續轉換將找到 TLB 命中，並且記憶體訪問將繼續。 轉換失敗 有兩種原因導致分頁表查詢失敗。第一種，如果該地址沒有可用的轉換，這意味該虛擬地址的儲存器訪問是無效的。這通常是程式錯誤導致，作業系統需要處理這個問題。現代作業系統會發送一個段錯誤訊號給出錯程式。 當物理記憶體中不存在這個頁，也會引起分頁表查詢失敗。如果請求的頁面被調出物理記憶體，給其他頁騰出空間，會引起這個錯誤。這種情況下，頁被分配到儲存在介質上的輔助儲存，例如硬碟。（這種輔助儲存，或叫備用儲存，如果是一個硬碟分割槽或者交換檔案，經常稱之為交換分割槽，如果是檔案，叫做分割槽檔案或頁檔案。）這時候，分頁需要從硬碟放回到物理記憶體中，這類操作通常會導致一種稱為系統抖動（thrashing）的情況，透過區域性性原理（principle of locality）來預測將來可能會訪問的塊，避免出現系統抖動。 當物理記憶體沒滿的時候，這是一個簡單操作。頁被寫回物理記憶體，頁表和轉換備用緩衝會更新，指令重啟。然而，當物理記憶體已滿，一個或多個頁要被調、為請求的頁面騰出空間時候。頁表需要更新，標識出那些在物理記憶體被調出的頁，然後標識那些從硬碟調入物理記憶體的頁。TLB 也需要更新，包括去掉調出的頁，重啟指令。頁的調入調出請見頁置換演算法。 分頁表資料 最簡單的分頁表系統通常維護一個幀表和一個分頁表。幀表處理幀對映資訊。更高階系統中，幀表可以處理頁屬於的地址空間，統計資訊和其他背景資訊。 分頁表處理頁的虛擬地址和物理幀的對映。還有一些輔助資訊，如當前存在標識位 present bit，髒資料標識位或已修改的標識位，地址空間或程序 ID 資訊。 輔助儲存，比如硬碟可以用於增加物理記憶體。頁可以調入和調出到物理記憶體和磁碟。當前存在標識位可以指出那些頁在物理記憶體，哪些頁在硬碟上。頁可以指出如何處理這些不同頁。是否從硬碟讀取一個頁，或把其他頁從物理記憶體調出。 髒資料標識位可以最佳化效能。一個頁從硬碟調入到物理記憶體中，讀取後調出，當頁沒有更改不需要寫回硬碟。但是如果頁在調入物理記憶體後被修改，會標記其為髒資料，意味著該頁必需被寫回備用儲存。這種策略需要當頁被調入到記憶體後，後備儲存保留一份頁的複製。有了髒資料標誌位，一些頁隨時會同時存在於物理記憶體和後備儲存中。 如果不是單地址空間作業系統，地址空間或程序 id 資訊是必要的，記憶體管理系統需要知道頁對應的程序。兩個不同意圖的程序可以使用兩個相同的虛擬地址。分頁表必需為兩個程序提供不同的虛擬記憶體。用虛擬記憶體頁關聯程序 ID 頁可以幫助選擇要調出的頁，當頁關聯到不活躍程序上，特別是那些主要內碼表被調出的程序，相比活躍程序需要頁的可能性會更小。 分頁表型別 有一些不同的分頁表型別，適合不同應用場景。本質上，準系統分頁表必需儲存虛擬地址，物理地址排在之後，還有一些可能的地址空間資訊。 倒排分頁表 倒排分頁表（IPT）被認為是一個標準 RAM 的 TLB 的 offchip 擴充套件。不同於一個真實的分頁表，IPT 不需要處理所有當前對映。作業系統要準備處理丟失，就像 mips 風格的軟體填充 TLB。 IPT 把分頁表和幀表結合成一個數據結構。其核心是一個固定大小的表，表的行數等於記憶體中的幀數。如果有 4000 個幀，倒排分頁表有 4000 行。每個行的表項對應虛擬記憶體頁碼，物理頁頁碼（不是物理地址），一些其他資料，建立碰撞鏈。 從所有 IPT 核心結構中搜索表項效率很低，所以我們用雜湊表來對映虛擬地址（或可能需要的地址空間 PID 資訊）對應的 IPT 索引，這裡會使用衝突鏈。雜湊表被稱作雜湊錨點表。雜湊方式沒對覆蓋率做通常的最佳化，原始速度更理想。當然，雜湊表會有衝突。由於這個雜湊方式，我們使用時候會經歷很多衝突，所以表中 VPN 建立的每個表項，會檢查是否是已被檢索的表項或衝突。 在搜尋對映時候，使用雜湊錨點表。如果沒有表項存在，會出現一個頁錯誤。否則，表項被找到。依賴於架構，表項被重新放入 TLB，記憶體指令重啟，或跟蹤衝突鏈直到結束，然後出現頁錯誤。 這種模式種，一個虛擬地址可以分成 2 部分。前半段是虛擬頁碼，後半段是頁中的偏移量。 這種設計的主要問題在於雜湊方式 cache 命中率較弱。基於樹的設計，忽略在分頁表表項中置換相鄰位置的相鄰頁。但是一個倒排分頁表把表項離散，會破壞引用的空間區域性性。為了減少這個問題，作業系統會使雜湊表空間最小，平衡增長的未命中比率。通常會有一個雜湊表，在物理記憶體中連續，共享給所有程序。記憶體碎片會導致預處理分頁表不現實，所以用一個預處理標識消除不同程序的頁的歧義。從程序中去掉分頁表項或許有點慢，作業系統會忽略重用預處理標識值，延遲面對這個問題，選擇忍受大量記憶體浪費，用於對映預處理雜湊表。 多級分頁表 倒排分頁表為所有物理記憶體中的幀，建立一個對映列表。但是這個可能會比較浪費。相反，我們透過保持一些覆蓋當前虛擬記憶體區塊的分頁表，建立一個包含虛擬頁對映的分頁表資料結構。比如，我們建立 1024 個小於 4K 的頁，覆蓋 4M 的虛擬記憶體。 這非常有用，因為通常虛擬記憶體的頂部和底部用於正在執行的程序，頂部通常用於文字和資料段，底部用於堆疊，空閒記憶體居中。多級分頁表會保持少量較小分頁表，僅覆蓋記憶體頂部和底部，只有確實需要時候才建立新的。每種較小分頁表被一個主分頁錶鏈接再一起，有效的建立一個樹型資料結構。需要不只 2 級，可能有多級。 這種模式下，一個虛擬地址可以分成三部分：根分頁表的索引，子分頁表的索引，子分頁表偏移量。多級分頁表也叫做分級分頁表。 虛擬分頁表 已經提到了，在虛擬地址空間中為每個虛擬頁建立分頁表結構，最終會導致浪費。但是我們可以把分頁表放入虛擬記憶體，允許虛擬記憶體管理分頁表記憶體，來避免過多空間被涉及。 但是一部分這種線性分頁表結構，需要一直存在於物理記憶體，來防範迴圈頁錯誤。會尋找一個不存在於分頁表中的重要部分，在當前分頁表中沒有。 巢狀分頁表 巢狀分頁表可以被用於增加硬體虛擬化的效能。為分頁表虛擬化提供硬體支援，會大大降低模擬的需要。x86 下虛擬化當前的選擇是 Intel 的擴充套件分頁表特性，和 AMD 的快速虛擬索引特性。 參考文獻 參見 轉譯後備緩衝區 快取檔案置換機制 指標 PaX WX Category 虛擬記憶體