虛擬記憶體與記憶體映射

需求分頁(demand paging)

需求分頁(demand paging)是一種策略:不到一頁真正第一次被用到的那一刻,就不把它帶進 RAM——按需載入,而非預先載入。它就像旅館不到客人即將走進房門前不去整理那間房:何必準備一個還沒人要的東西?這正是為什麼一支程式能瞬間啟動、配置好幾 GB 卻幾乎不花成本,直到被碰觸為止。

它的運作步驟如下。當作業系統建立一支程式或核准一大筆配置時,它並不把位元組複製進 RAM;它只在分頁表裡把那些頁標成「不存在」,記下真正內容住在哪(磁碟上的某個檔案,或「全是零」)。程式執行,當它第一次讀或寫其中一頁時,MMU 看到「不存在」位元就引發一次分頁錯誤。作業系統接住它、找一個空閒頁框、把正確內容填進該框(從可執行檔讀、從磁碟讀,或對全新記憶體填零)、把分頁表項修成「存在」,並重新執行那條指令。從那一刻起這一頁就常駐且快速;從未被碰過的頁則根本不會載入。

回報很大:更快的啟動(只有真正執行到的程式碼才被分頁進來)、更低的記憶體用量(沒碰過的配置不花成本),以及能執行比實際所需常駐量還大的程式。誠實的提醒在於時機:載入的成本是在第一次碰觸時、以分頁錯誤的形式付出,散布在整個執行過程而非一開始。若那些首觸錯誤需要讀磁碟(主要錯誤),它們會讓工作負載的前段感覺遲緩。

char *p = malloc(100 * 1024 * 1024); 立刻回傳,幾乎不用任何實體 RAM。只有當你的迴圈寫進一頁又一頁時,每一頁才被錯誤帶進來,一次一頁 4 KiB,於是 RAM 用量隨你真正碰觸記憶體而逐步攀升。

配置很便宜;成本在第一次碰觸時才到來。

這正是為什麼一次成功的 malloc() 並不保證記憶體真的已經在那裡——那些頁是被「承諾」的,而非「實際投入」的。在允許記憶體超額配置(overcommit)的系統上,短缺可能在很久之後才浮現,以一次失敗的錯誤或 OOM killer 的形式,而非在 malloc() 那一刻。

又稱
lazy loading of pagesdemand-zero paging按需分頁