分頁與位址轉換

共享頁(shared pages)

想像一百個學生都需要同一本參考教科書。圖書館可以買一百本,浪費架位與金錢——或者只留「一本」,讓大家都來查閱。共享頁就是記憶體裡的第二種做法:某些頁(一個程式庫的程式碼、一張唯讀的資料表、一段明確共享的記憶體區)只有「一份」實體副本,卻同時被對應進「許多」行程,於是它們全都使用相同的頁框,而不必各自帶一份私有的複本。

分頁讓這件事乾淨俐落的原理如下。回想每個行程都有自己的分頁表,而頁號是各自獨立地對應到頁框。要共享,作業系統只需讓數個行程的分頁表項目指向「相同」的實體頁框。於是行程 A 的頁 5 與行程 B 的頁 9 可以都指名頁框 200;記憶體裡一份副本,兩個(或多個)對應指向它。注意,共享頁在每個行程裡可以出現在「不同」的頁號——分頁表把這件事藏了起來。對程式碼而言,這要求程式碼是「可重入的」(也稱純程式碼):永不自我修改、且不在自己的頁裡保留任何個別使用者狀態的程式碼,如此才能安全地讓多個行程同時執行。共享頁通常在分頁表項目裡被標為唯讀與可執行,這既強制它們維持不被修改,也讓硬體保證沒有任何行程能破壞那份共享副本。

共享頁之所以重要,是因為它省下大量實體記憶體:像 C 執行期這樣的標準程式庫可以只載入一次、被每個使用它的行程共享,而非重複幾十份。它們也是透過共享記憶體區進行快速行程間通訊的基礎,更是寫入時複製的根基——一頁先被共享,直到有人寫入它為止。誠實的提醒是:共享只對「不被私下修改」的內容才安全:可寫的資料一般不能天真地共享(某行程的寫入會破壞其他行程),這正是共享頁通常唯讀的原因,也是寫入時複製存在、以處理共享頁必須分道揚鑣那一刻的原因。

四十個行程全都使用同一個共享程式庫。它的程式碼佔頁框 200 到 219。每個行程的分頁表把自己的頁對應到那同樣的 20 個頁框,標為讀與執行、禁止寫入。結果:20 個頁框的程式碼服務全部四十個行程,而非 40 * 20 = 800 個頁框。

許多分頁表指向相同的頁框;可重入的唯讀程式碼只共享一份,而非每個行程各複製一份。

共享只對「不被私下修改」的內容才安全——因此共享頁通常唯讀,且程式碼必須可重入。天真地共享可寫資料會讓某行程破壞其他行程;寫入時複製的存在,正是為了處理共享頁必須分道揚鑣的那一刻。

又稱
shared memory pagesshared frames共享頁面共用頁