1. 程式人生 > 其它 >Linux寫時拷貝技術(copy-on-write)

Linux寫時拷貝技術(copy-on-write)

源於網上資料

COW技術初窺:

      在Linux程式中,fork()會產生一個和父程序完全相同的子程序,但子程序在此後多會exec系統呼叫,出於效率考慮,linux中引入了“寫時複製“技術,也就是隻有程序空間的各段的內容要發生變化時,才會將父程序的內容複製一份給子程序。

      那麼子程序的物理空間沒有程式碼,怎麼去取指令執行exec系統呼叫呢?

      在fork之後exec之前兩個程序用的是相同的物理空間(記憶體區),子程序的程式碼段、資料段、堆疊都是指向父程序的物理空間,也就是說,兩者的虛擬空間不同,但其對應的物理空間是同一個。當父子程序中有更改相應段的行為發生時,再為子程序相應的段分配物理空間,如果不是因為exec,核心會給子程序的資料段、堆疊段分配相應的物理空間(至此兩者有各自的程序空間,互不影響),而程式碼段繼續共享父程序的物理空間(兩者的程式碼完全相同)。而如果是因為exec,由於兩者執行的程式碼不同,子程序的程式碼段也會分配單獨的物理空間。      

      在網上看到還有個細節問題就是,fork之後核心會通過將子程序放在佇列的前面,以讓子程序先執行,以免父程序執行導致寫時複製,而後子程序執行exec系統呼叫,因無意義的複製而造成效率的下降。

 

COW詳述:

     現在有一個父程序P1,這是一個主體,那麼它是有靈魂也就身體的。現在在其虛擬地址空間(有相應的資料結構表示)上有:正文段,資料段,堆,棧這四個部分,相應的,核心要為這四個部分分配各自的物理塊。即:正文段塊,資料段塊,堆塊,棧塊。至於如何分配,這是核心去做的事,在此不詳述。

1.      現在P1用fork()函式為程序建立一個子程序P2,

核心:

(1)複製P1的正文段,資料段,堆,棧這四個部分,注意是其內容相同。

(2)為這四個部分分配物理塊,P2的:正文段->PI的正文段的物理塊,其實就是不為P2分配正文段塊,讓P2的正文段指向P1的正文段塊,資料段->P2自己的資料段塊(為其分配對應的塊),堆->P2自己的堆塊,棧->P2自己的棧塊。如下圖所示:同左到右大的方向箭頭表示複製內容。

 

2.       寫時複製技術:核心只為新生成的子程序建立虛擬空間結構,它們來複制於父程序的虛擬究竟結構,但是不為這些段分配實體記憶體,它們共享父程序的物理空間,當父子程序中有更改相應段的行為發生時,再為子程序相應的段分配物理空間。

 

 

3.       vfork():這個做法更加火爆,核心連子程序的虛擬地址空間結構也不建立了,直接共享了父程序的虛擬空間,當然了,這種做法就順水推舟的共享了父程序的物理空間

 

通過以上的分析,相信大家對程序有個深入的認識,它是怎麼一層層體現出自己來的,程序是一個主體,那麼它就有靈魂與身體,系統必須為實現它建立相應的實體, 靈魂實體與物理實體。這兩者在系統中都有相應的資料結構表示,物理實體更是體現了它的物理意義。以下援引LKD

     傳統的fork()系統呼叫直接把所有的資源複製給新建立的程序。這種實現過於簡單並且效率低下,因為它拷貝的資料也許並不共享,更糟的情況是,如果新程序打算立即執行一個新的映像,那麼所有的拷貝都將前功盡棄。Linux的fork()使用寫時拷貝(copy-on-write)頁實現。寫時拷貝是一種可以推遲甚至免除拷貝資料的技術。核心此時並不複製整個程序地址空間,而是讓父程序和子程序共享同一個拷貝。只有在需要寫入的時候,資料才會被複制,從而使各個程序擁有各自的拷貝。也就是說,資源的複製只有在需要寫入的時候才進行,在此之前,只是以只讀方式共享。這種技術使地址空間上的頁的拷貝被推遲到實際發生寫入的時候。在頁根本不會被寫入的情況下—舉例來說,fork()後立即呼叫exec()—它們就無需複製了。fork()的實際開銷就是複製父程序的頁表以及給子程序建立惟一的程序描述符。在一般情況下,程序建立後都會馬上執行一個可執行的檔案,這種優化可以避免拷貝大量根本就不會被使用的資料(地址空間裡常常包含數十兆的資料)。由於Unix強調程序快速執行的能力,所以這個優化是很重要的。這裡補充一點:Linux COW與exec沒有必然聯絡

 

 

PS:實際上COW技術不僅僅在Linux程序上有應用,其他例如C++的String在有的IDE環境下也支援COW技術,即例如:

string str1 = "hello world";
string str2 = str1;

之後執行程式碼:

str1[1]='q';
str2[1]='w';

在開始的兩個語句後,str1和str2存放資料的地址是一樣的,而在修改內容後,str1的地址發生了變化,而str2的地址還是原來的,這就是C++中的COW技術的應用,不過VS2005似乎已經不支援COW。