虛擬記憶體與記憶體映射

寫入時複製分頁(copy-on-write)

寫入時複製(copy-on-write,COW)是一種懶惰複製的把戲:當兩方理應各自擁有某份資料的副本、但都還沒改動它時,就讓它們共用單一份實體副本,只在其中一方試圖寫入的那一刻,才真正做出一份獨立的複本。它就像兩個人拿到同一份標著「唯讀」的共享文件——只要雙方都只讀,一份就夠了;某方想在上面塗寫的那一刻,他得先拿到自己的影印本。

在機制上,它是用分頁表位元做出來的。共享的頁被對映進雙方的定址空間、指向相同的實體頁框,但每一筆這樣的分頁表項都被標成唯讀,即使資料邏輯上是可寫的。讀取直接通過,可以自由共享。當任一方寫入時,唯讀位元讓 MMU 引發一次保護分頁錯誤;作業系統接住它、配置一個新頁框、把那一頁的內容複製進去、把寫入者的分頁表項指向新的私有頁框並設為可寫、再重新執行那次寫入。只有真正被寫到的頁才會被複製——一切沒碰過的都維持共享。

經典使用者是 fork()。天真的 fork 會把父行程整個定址空間複製給子行程,那可能有好幾 GB,而且幾乎總是緊接著被一個 exec() 丟掉。取而代之,fork() 把所有共享的頁標成寫入時複製,於是父子行程瞬間共用實體記憶體,只有任一方修改到的寥寥幾頁才被複製。這讓 fork() 很便宜,也是為什麼建立一個行程再 exec 一支新程式很快。同一機制也支撐共享零頁與檔案的共享對映。

在 fork() 之後,父子行程以唯讀方式共享相同的實體頁。父行程在某個共享頁上執行 x = 5;;那次寫入引發錯誤,作業系統只複製那一頁,於是現在父子各有它的獨立副本——其餘它們從沒寫過的頁都維持共享。

寫入前共享;只有被寫到的那一頁被複製。

寫入時複製讓 fork() 很便宜,但複製並非免費——它只是被延後到每一頁的第一次寫入。一個立刻改寫大量繼承記憶體的子行程,會觸發一連串這類錯誤,所以「fork 很便宜」只在子行程於 exec() 前寫得很少時才成立。

又稱
COWlazy copying寫時複製