Linux

fork() 中的寫時複製如何處理多個分叉?

  • July 23, 2018

根據維基百科(這可能是錯誤的)

當發出 fork() 系統呼叫時,將創建與父程序對應的所有頁面的副本,並由作業系統為子程序載入到單獨的記憶體位置。但在某些情況下不需要這樣做。考慮當孩子執行“ exec”系統呼叫(用於從 C 程序中執行任何執行檔)或在fork(). 當只需要子程序為父程序執行命令時,不需要複製父程序的頁面,因為exec將呼叫它的程序的地址空間替換為要執行的命令。

在這種情況下,將使用一種稱為寫時複製 (COW) 的技術。使用這種技術,當發生分叉時,不會為子程序複製父程序的頁面。相反,頁面在子程序和父程序之間共享。每當程序(父程序或子程序)修改頁面時,都會為執行修改的程序(父程序或子程序)單獨製作該特定頁面的單獨副本。然後,此過程將使用新複製的頁面,而不是在所有未來引用中共享的頁面。另一個程序(沒有修改共享頁面的程序)繼續使用頁面的原始副本(現在不再共享)。這種技術被稱為寫時複製,因為當某些程序寫入時頁面被複製。

似乎當任何一個程序嘗試寫入頁面時,頁面的新副本被分配並分配給生成頁面錯誤的程序。之後原始頁面被標記為可寫。

我的問題是:如果fork()在任何程序嘗試寫入共享頁面之前多次呼叫會發生什麼?

沒有什麼特別的事情發生。所有程序都共享同一組頁面,並且每個程序在想要修改頁面時都會獲得自己的私有副本。

fork() 的行為取決於 *nix 系統是否有 MMU。在非 MMU 系統(如早期的 PDP-11)上,fork() 系統呼叫為每個子代複製了所有父代的記憶體。在基於 MMU 的 *nix 系統上,核心將所有非堆棧頁面標記為 R/O,並在父子節點之間共享它們。然後,當任一程序寫入任何頁面時,MMU 會擷取該嘗試,然後核心分配一個可寫頁面並更新 MMU 頁表以指向現在可寫的頁面。這種寫時複製行為提供了加速,因為最初只需要為每個子程序分配和複製一個私有堆棧。

如果您在每個 fork() 呼叫之間執行一些父程式碼,那么生成的子程序將因父程序已更改的頁面而異。另一方面,如果父程序簡單地發出多個fork() 呼叫,例如在一個循環中,那麼子程序將幾乎相同。如果使用局部循環變數,那麼在每個孩子的堆棧中都會有所不同。

引用自:https://unix.stackexchange.com/questions/58145