Copy-On-Write技術

linux內核在使用fork創建進程時,基本上會使用Copy-On-Write(COW)技術。這裏解釋一下COW技術以及爲什麼在fork中使用。

WIKI上對COW的解釋:

Copy-on-write (sometimes referred to as "COW") is an optimization strategy used in computer programming. The fundamental idea is that if multiple callers ask for resources which are initially indistinguishable, they can all be given pointers to the same resource. This function can be maintained until a caller tries to modify its "copy" of the resource, at which point a true private copy is created to prevent the changes becoming visible to everyone else. All of this happens transparently to the callers. The primary advantage is that if a caller never makes any modifications, no private copy need ever be created.

意思上就是:在複製一個對象的時候並不是真正的把原先的對象複製到內存的另外一個位置上,而是在新對象的內存映射表中設置一個指針,指向源對象的位置,並把那塊內存的Copy-On-Write位設置爲1.

這樣,在對新的對象執行讀操作的時候,內存數據不發生任何變動,直接執行讀操作;而在對新的對象執行寫操作時,將真正的對象複製到新的內存地址中,並修改新對象的內存映射表指向這個新的位置,並在新的內存位置上執行寫操作。

這個技術需要跟虛擬內存和分頁同時使用,好處就是在執行復制操作時因爲不是真正的內存複製,而只是建立了一個指針,因而大大提高效率。但這不是一直成立的,如果在複製新對象之後,大部分對象都還需要繼續進行寫操作會產生大量的分頁錯誤,得不償失。所以COW高效的情況只是在複製新對象之後,在一小部分的內存分頁上進行寫操作。

COW在編程中被廣泛應用。

特別是在操作系統當中,當一個程序運行結束時,操作系統並不會急着把其清除出內存,原因是有可能程序還會馬上再運行一次(從磁盤把程序裝入到內存是個很慢的過程),而只有當內存不夠用了,纔會把這些還駐留內存的程序清出。

而對於Linux內核空間創建進程時的fork,由於在內核空間已經由代碼決定不使用COW技術(參見mm/memory.c Line 221)。從而由內核空間的進程0(main)創建進程1(init)不使用COW,系統對此次新進程創建進行了特殊處理(存在疑問,同樣是fork,如何實現對這個fork的特殊處理,估計是schedule,看到再解決了)。進程0和進程1同時使用着內核代碼區內(<=1M)相同的代碼和數據內存頁面(640KB),只是執行代碼不在一處,因此他們也同時使用着相同的用戶堆棧區。在爲進程1(init)複製其父進程(進程0)的頁目錄和頁表項時,進程0的640KB頁表項的屬性沒有改動過(仍然可讀寫),但是進程1的640KB對應的頁表項卻被設置成只讀。因此當進程1(init)開始執行時,對用戶堆棧的入棧操作將導致頁面寫保護異常,從而使得內核的內存管理程序爲進程1在主內存區中分配一內存頁面,並把進程0中的頁面內容複製到新的頁面上。從此時開始,進程1開始有自己獨立的內存頁面,由於此時的內存頁面在主內存區,因此進程1中繼續創建新的子進程時可以採用COW技術。

在Linux內核首先通過move_to_user_mode轉移到用戶模式下執行,至此main函數就以進程0的身份運行。而進程0是所有將創建進程的父進程,他創建進程1(init)時,fork的結果就是進程1與進程0擁有完全相同的內存空間、堆棧,這時進程0和進程1的內存還都在Linux內核空間中。

內核調度進程運行時次序是隨機的,有可能在進程0創建了進城1之後仍然允許進程0,由於兩個進程共享內存空間,爲了不出現衝突問題,就必須要求進程0在進程1執行堆棧操作(進程1的堆棧操作會導致頁面保護異常,從而使得進程1在主內存區得到新的用戶頁面區,此時進程1和進程0纔算是真正獨立,如前面所述)之前禁止使用用戶堆棧區。所以進程0在執行了fork(創建了進程1)之後的pause使用內嵌的方式,保證進程0(main)不會弄亂堆棧。

進程1中如果執行fork以及exec,此時的頁面空間已經到了主內存區,就可以使用COW了。


發佈了12 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章