Copy-On-Write技術

wtjiang2008發表於2014-03-13

linux核心在使用fork建立程式時,基本上會使用Copy-On-Write(COW)技術。這裡解釋一下COW技術以及為什麼在fork中使用。

WIKI上對COW的解釋:

Copy-on-write (sometimes referred to as "COW") is an  strategy used in . 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  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了。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/527318/viewspace-1118515/,如需轉載,請註明出處,否則將追究法律責任。

相關文章