分頁(paging)
想像你正在搬家,有一堆家當必須放進一座倉儲倉庫。舊做法是要求一整段連續、剛好等於整堆家當大小的層架空間——但倉庫裡早已到處散著零零碎碎的空層架,從來湊不出一段夠大的,於是即使總空間綽綽有餘,你還是被拒於門外。分頁就是巧妙的解法:把家當切成大小一模一樣的箱子,讓每個箱子放進「任何一個」空的層架格,順序也不拘。這些箱子不必彼此相鄰;另有一本小筆記本記下:第 1 箱放到哪一格、第 2 箱放到哪一格,依此類推。如今任何零散的空格都派得上用場。
具體來說,分頁是一種記憶體管理方案,它把一個行程的邏輯(虛擬)位址空間切成固定大小的區塊,稱為頁(page),並把實體記憶體切成「相同」大小的區塊,稱為頁框(frame)。一個頁可以被載入任何一個空閒的頁框;這個對應關係記在每個行程各自的分頁表(page table)裡,每個頁一筆項目,記著裝著它的頁框。由於頁與頁框大小相同且固定,配置只是簡單的記帳(維護一張空閒頁框清單,隨便發一個出去),而一個行程的諸多頁可以撒得滿實體記憶體都是,對程式而言卻仍像一整段連續的位址空間。硬體會悄悄地、針對程式用到的每一個邏輯位址,透過分頁表把它翻譯成真正的實體位址。
分頁之所以重要,是因為它「消除了外部碎裂」——連續配置會留下那些零碎、無法利用的空閒記憶體小縫,而分頁讓任何空閒頁框都同樣好用,於是這個問題消失。誠實的代價是一點點「內部碎裂」:行程的最後一頁通常裝不滿,因此平均每個行程大約浪費半頁。分頁是現代作業系統的主流方案,也是虛擬記憶體賴以建立的基礎;但要注意,分頁本身只是位址對應的機制;按需從磁碟把頁取進來則是另一個概念(需求分頁),在別處說明。
某行程需要 13 KB 記憶體,頁大小為 4 KB。分頁給它 4 頁:頁 0、1、2 是滿的(12 KB),頁 3 只裝 1 KB。作業系統找出任意 4 個空閒頁框——比如頁框 9、2、17、5——並記下對應:頁 0 → 頁框 9、頁 1 → 頁框 2、頁 2 → 頁框 17、頁 3 → 頁框 5。這些頁框不必相鄰。
四個等大的頁被撒進四個不相鄰的頁框;頁 3 只裝了四分之一,這就是內部碎裂。
分頁去除了「外部」碎裂,卻造成一點點「內部」碎裂(最後那一頁裝不滿)。常見的誤解是以為分頁完全不浪費記憶體——其實平均每個行程約損失半頁。