2015-06-21 54 views
2

從我的問題「叉子創建一個與其父母完全相同的新過程」的標題中作出的假設。我想知道一個分支是如何由操作系統真正實現的。Fork創建一個新的過程,它的父母完全一樣

考慮到一個繁重的過程(巨大的RAM佔用空間),它叉自己完成一個小任務(列出文件到一個目錄)。從這個假設來看,我期望孩子的過程會像第一個那樣大。不過,我的常識告訴我,情況並非如此。

它是如何在現實世界中工作的?

+2

https://en.wikipedia.org/wiki/Copy-on-write在這裏可能會有幫助 – Jasper

+0

@Jasper你是說可執行代碼位於RAM中,並且兩個進程共享相同的內存空間? – nowox

+1

@nowox「man 2 fork」可以幫助你很多。 – c4f4t0r

回答

3

正如在評論中提到別人,一種叫做寫入時複製減輕了複製父進程的整個內存空間的成本。寫入時複製意味着內存頁面在父節點與子節點之間以只讀方式共享,直到它們中的任何一個決定寫入 - 在此時複製頁面,並且每個進程都獲得它自己的私人副本。這種技術很容易防止大量複製,在很多情況下會浪費時間,因爲孩子會做出一些簡單的事情並退出。

下面是具體發生了什麼:

當你調用fork(2),也導致了唯一直接成本分配一個新的獨特的工藝描述符和複製母公司的頁表的費用成本。在Linux中,fork(2)clone(2)系統調用實現,該調用是一個更一般的系統調用,它允許調用者控制新進程的哪些部分與父進程共享。當從fork(2)調用時,會傳遞一組標誌以指示不共享任何內容(您可以選擇共享內存,文件描述符等 - 這就是線程的實現方式:通過調用clone(2)CLONE_VM,這意味着「共享內存空間「)。

在引擎蓋下,每個進程的內存頁面都有一個標誌位,即寫時複製標誌,該標誌指示在寫入之前是否應該複製該頁面。 fork(2)用該位標記進程中的每個可寫頁面。每個頁面還保持一個引用計數。

因此,當進程分叉時,內核在該進程的每個非私有可寫頁面上設置寫時拷貝位,並將引用計數遞增1。子進程有指向這些相同頁面的指針。

然後,每個頁面被標記爲只讀,以便嘗試寫入頁面會生成頁面錯誤 - 這是喚醒內核所需的,以便它有機會看到發生了什麼以及需要什麼完成。

當其中一個進程寫入仍然共享的頁面,因此被標記爲只讀時,內核會喚醒並試圖找出頁面錯誤的原因。假設父/子進程正在寫入合法位置,內核最終會看到頁面錯誤已生成,因爲該頁面被標記爲copy-on-write並且該頁面有多個引用。

內核然後分配內存,將頁面複製到新位置,然後寫入可以繼續。

什麼是跨越不同叉

你說fork(2)創建一個新的過程,是完全一樣其父。這不完全正確。有家長和孩子之間的一些差異:

  1. 進程ID是不同
  2. 父進程ID是不同
  3. 孩子的資源使用率(CPU時間等)被設置爲0
  4. 由母公司擁有
  5. 文件鎖不被繼承
  6. 孩子上一組待決的信號被清除
  7. 未決報警是在孩子清除

關於vfork的

vfork(2)系統調用非常相似fork(),但它絕對沒有複製 - 它甚至沒有複製父頁表。隨着寫入時拷貝的引入,它不再被廣泛使用,但歷史上它被分支後的進程使用exec()

當然,在vfork()導致混亂之後試圖寫入子進程中的內存。

1

當一個進程分叉,子進程使用同一頁表作爲它的父util的父母或子女寫信給它的空間!所以

相關問題