C語言中文網
首頁 > 編程筆記 > 操作系統筆記 閱讀:811

寫時復制技術(詳解版)

我們知道了一個進程如何采用請求調頁,僅調入包括第一條指令的頁面,從而能夠很 快開始執行。然而,通過系統調用 fork() 的進程創建最初可以通過使用類似于頁面共享的技術,繞過請求調頁的需要。這種技術提供了快速的進程創建,并最小化必須分配給新創建進程的新頁面的數量。

回想一下,系統調用 fork() 創建了父進程的一個復制,以作為子進程。傳統上,fork() 為子進程創建一個父進程地址空間的副本,復制屬于父進程的頁面。然而,考慮到許多子進程在創建之后立即調用系統調用 exec(),父進程地址空間的復制可能沒有必要。

因此,可以采用一種稱為寫時復制的技術,它通過允許父進程和子進程最初共享相同的頁面來工作。這些共享頁面標記為寫時復制,這意味著如果任何一個進程寫入共享頁面,那么就創建共享頁面的副本。

進程1修改頁面C前后
圖 1 進程 1 修改頁面 C 前后

寫時復制如圖 1 所示,圖中分別反映了修改頁面 C 的前與后。

例如,假設子進程試圖修改包含部分堆棧的頁面,并且設置為寫時復制。操作系統會創建這個頁面的副本,將其映射到子進程的地址空間。然后,子進程會修改復制的頁面,而不是屬于父進程的頁面。顯然,當使用寫時復制技術時,僅復制任何一進程修改的頁面,所有未修改的頁面可以由父進程和子進程共享。

還要注意,只有可以修改的頁面才需要標記為寫時復制。不能修改的頁面(包含可執行代碼的頁面)可以由父進程和子進程共享。寫時復制是一種常用技術,為許多操作系統所采用,包括Windows XP、Linux 和 Solaris。

當確定采用寫時復制來復制頁面時,重要的是注意空閑頁面的分配位置。許多操作系統為這類請求提供了一個空閑的頁面池。當進程的堆棧或堆要擴展時或有寫時復制頁面需要管理時,通常分配這些空閑頁面。操作系統分配這些頁面通常采用稱為按需填零的技術。按需填零頁面在需要分配之前先填零,因此清除了以前的內容。

UNIX 的多個版本(包括 Solaris 和 Linux)提供了系統調用 fork() 的變種,即 vfork()(虛擬內存fork(virtual memory fork)),vfork() 的操作不同于寫時復制的fork()。

采用 vfork(),父進程被掛起,子進程使用父進程的地址空間。因為 vfork() 不采用寫時復制,如果子進程修改父地址空間的任何頁面,那么這些修改過的頁面對于恢復的父進程是可見的。因此,應謹慎使用 vfork(),以確保子進程不會修改父進程的地址空間。當子進程在創建后立即調用 exec() 時,可使用 vfork()。因為沒有復制頁面,vfork() 是一個非常有效的進程創建方法,有時用于實現 UNIX 命令外殼接口。

所有教程

優秀文章

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo