linux写时复制技术初探
COW技術(shù)初窺:
在Linux程序中,fork()會(huì)產(chǎn)生一個(gè)和父進(jìn)程完全相同的子進(jìn)程,但子進(jìn)程在此后多會(huì)exec系統(tǒng)調(diào)用,出于效率考慮,linux中引入了“寫時(shí)復(fù)制“技術(shù),也就是只有進(jìn)程空間的各段的內(nèi)容要發(fā)生變化時(shí),才會(huì)將父進(jìn)程的內(nèi)容復(fù)制一份給子進(jìn)程。
那么子進(jìn)程的物理空間沒有代碼,怎么去取指令執(zhí)行exec系統(tǒng)調(diào)用呢?
在fork之后exec之前兩個(gè)進(jìn)程用的是相同的物理空間(內(nèi)存區(qū)),子進(jìn)程的代碼段、數(shù)據(jù)段、堆棧都是指向父進(jìn)程的物理空間,也就是說,兩者的虛擬空間不同,但其對(duì)應(yīng)的物理空間是同一個(gè)。當(dāng)父子進(jìn)程中有更改相應(yīng)段的行為發(fā)生時(shí),再為子進(jìn)程相應(yīng)的段分配物理空間,如果不是因?yàn)閑xec,內(nèi)核會(huì)給子進(jìn)程的數(shù)據(jù)段、堆棧段分配相應(yīng)的物理空間(至此兩者有各自的進(jìn)程空間,互不影響),而代碼段繼續(xù)共享父進(jìn)程的物理空間(兩者的代碼完全相同)。而如果是因?yàn)閑xec,由于兩者執(zhí)行的代碼不同,子進(jìn)程的代碼段也會(huì)分配單獨(dú)的物理空間。
在網(wǎng)上看到還有個(gè)細(xì)節(jié)問題就是,fork之后內(nèi)核會(huì)通過將子進(jìn)程放在隊(duì)列的前面,以讓子進(jìn)程先執(zhí)行,以免父進(jìn)程執(zhí)行導(dǎo)致寫時(shí)復(fù)制,而后子進(jìn)程執(zhí)行exec系統(tǒng)調(diào)用,因無意義的復(fù)制而造成效率的下降。
COW詳述:
- 現(xiàn)在有一個(gè)父進(jìn)程P1,這是一個(gè)主體,那么它是有靈魂也就身體的。現(xiàn)在在其虛擬地址空間(有相應(yīng)的數(shù)據(jù)結(jié)構(gòu)表示)上有:正文段,數(shù)據(jù)段,堆,棧這四個(gè)部分,相應(yīng)的,內(nèi)核要為這四個(gè)部分分配各自的物理塊。即:正文段塊,數(shù)據(jù)段塊,堆塊,棧塊。至于如何分配,這是內(nèi)核去做的事,在此不詳述。
內(nèi)核:
(1)復(fù)制P1的正文段,數(shù)據(jù)段,堆,棧這四個(gè)部分,注意是其內(nèi)容相同。
(2)為這四個(gè)部分分配物理塊,P2的:正文段->PI的正文段的物理塊,其實(shí)就是不為P2分配正文段塊,讓P2的正文段指向P1的正文段塊,數(shù)據(jù)段->P2自己的數(shù)據(jù)段塊(為其分配對(duì)應(yīng)的塊),堆->P2自己的堆塊,棧->P2自己的棧塊。如下圖所示:同左到右大的方向箭頭表示復(fù)制內(nèi)容。
寫時(shí)復(fù)制技術(shù): 內(nèi)核只為新生成的子進(jìn)程創(chuàng)建虛擬空間結(jié)構(gòu),它們來復(fù)制于父進(jìn)程的虛擬究竟結(jié)構(gòu),但是不為這些段分配物理內(nèi)存,它們共享父進(jìn)程的物理空間,當(dāng)父子進(jìn)程中有更改相應(yīng)段的行為發(fā)生時(shí),再為子進(jìn)程相應(yīng)的段分配物理空間。
vfork():這個(gè)做法更加火爆,內(nèi)核連子進(jìn)程的虛擬地址空間結(jié)構(gòu)也不創(chuàng)建了,直接共享了父進(jìn)程的虛擬空間,當(dāng)然了,這種做法就順?biāo)浦鄣墓蚕砹烁高M(jìn)程的物理空間
通過以上的分析,相信大家對(duì)進(jìn)程有個(gè)深入的認(rèn)識(shí),它是怎么一層層體現(xiàn)出自己來的,進(jìn)程是一個(gè)主體,那么它就有靈魂與身體,系統(tǒng)必須為實(shí)現(xiàn)它創(chuàng)建相應(yīng)的實(shí)體, 靈魂實(shí)體與物理實(shí)體。這兩者在系統(tǒng)中都有相應(yīng)的數(shù)據(jù)結(jié)構(gòu)表示,物理實(shí)體更是體現(xiàn)了它的物理意義。以下援引LKD
傳統(tǒng)的fork()系統(tǒng)調(diào)用直接把所有的資源復(fù)制給新創(chuàng)建的進(jìn)程。這種實(shí)現(xiàn)過于簡(jiǎn)單并且效率低下,因?yàn)樗截惖臄?shù)據(jù)也許并不共享,更糟的情況是,如果新進(jìn)程打算立即執(zhí)行一個(gè)新的映像,那么所有的拷貝都將前功盡棄。Linux的fork()使用寫時(shí)拷貝(copy-on-write)頁(yè)實(shí)現(xiàn)。寫時(shí)拷貝是一種可以推遲甚至免除拷貝數(shù)據(jù)的技術(shù)。內(nèi)核此時(shí)并不復(fù)制整個(gè)進(jìn)程地址空間,而是讓父進(jìn)程和子進(jìn)程共享同一個(gè)拷貝。只有在需要寫入的時(shí)候,數(shù)據(jù)才會(huì)被復(fù)制,從而使各個(gè)進(jìn)程擁有各自的拷貝。也就是說,資源的復(fù)制只有在需要寫入的時(shí)候才進(jìn)行,在此之前,只是以只讀方式共享。這種技術(shù)使地址空間上的頁(yè)的拷貝被推遲到實(shí)際發(fā)生寫入的時(shí)候。在頁(yè)根本不會(huì)被寫入的情況下—舉例來說,fork()后立即調(diào)用exec()—它們就無需復(fù)制了。fork()的實(shí)際開銷就是復(fù)制父進(jìn)程的頁(yè)表以及給子進(jìn)程創(chuàng)建惟一的進(jìn)程描述符。在一般情況下,進(jìn)程創(chuàng)建后都會(huì)馬上運(yùn)行一個(gè)可執(zhí)行的文件,這種優(yōu)化可以避免拷貝大量根本就不會(huì)被使用的數(shù)據(jù)(地址空間里常常包含數(shù)十兆的數(shù)據(jù))。由于Unix強(qiáng)調(diào)進(jìn)程快速執(zhí)行的能力,所以這個(gè)優(yōu)化是很重要的。這里補(bǔ)充一點(diǎn):Linux COW與exec沒有必然聯(lián)系
實(shí)際上COW技術(shù)不僅僅在Linux進(jìn)程上有應(yīng)用,其他例如C++的String在有的IDE環(huán)境下也支持COW技術(shù),即例如:
string str1 = "hello world"; string str2 = str1;之后執(zhí)行代碼:
str1[1]='q'; str2[1]='w';在開始的兩個(gè)語句后,str1和str2存放數(shù)據(jù)的地址是一樣的,而在修改內(nèi)容后,str1的地址發(fā)生了變化,而str2的地址還是原來的,這就是C++中的COW技術(shù)的應(yīng)用,不過VS2005似乎已經(jīng)不支持COW。
知識(shí)拓展
轉(zhuǎn)載于:https://www.cnblogs.com/readlearn/p/10806393.html
總結(jié)
以上是生活随笔為你收集整理的linux写时复制技术初探的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [20181220]使用提示OR_EXP
- 下一篇: 越秀人民币夹层二期完成首轮关账 首期募集