日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Linux-Copy On Write写时复制机制初探

發(fā)布時間:2025/3/21 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux-Copy On Write写时复制机制初探 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

  • 生猛干貨
  • COW概述
  • *Unix
    • fork
    • 函數(shù)族exec( )
  • 為什么有了COW?
  • COW 原理
  • COW的優(yōu)缺點(diǎn)
  • 小結(jié)
  • 搞定Linux核心技術(shù)

生猛干貨

從系統(tǒng)安裝到程序員必備的Linux技能,還原真實(shí)工作場景,手把手帶你實(shí)戰(zhàn)演練


COW概述

來看下 https://en.wikipedia.org/wiki/Copy-on-write的說明

Copy-on-write (COW), sometimes referred to as implicit sharing[1] or shadowing,[2] is a resource-management technique used in computer programming to efficiently implement a “duplicate” or “copy” operation on modifiable resources.[3] If a resource is duplicated but not modified, it is not necessary to create a new resource; the resource can be shared between the copy and the original. Modifications must still create a copy, hence the technique: the copy operation is deferred to the first write. By sharing resources in this way, it is possible to significantly reduce the resource consumption of unmodified copies, while adding a small overhead to resource-modifying operations.

寫入時復(fù)制(COW),有時也稱為隱式共享,是一種計(jì)算機(jī)管理中用來有效地對可修改資源執(zhí)行“復(fù)制”操作的資源管理技術(shù)。

如果資源重復(fù)但未修改,則無需創(chuàng)建新資源,資源可以在副本和原始副本之間共享。

修改仍然必須創(chuàng)建一個副本,因此使用COW,可以將復(fù)制操作推遲到第一次寫入。

通過以這種方式共享資源,可以顯著減少未修改副本的資源消耗,當(dāng)然了資源修改操作的時候也會增加少量開銷。

簡單來說 COW 寫時復(fù)制是提高資源使用效率的一種手段, 在內(nèi)存管理(進(jìn)程的 fork),數(shù)據(jù)存儲( 比如 Docker 的 AUFS 文件系統(tǒng)),軟件開發(fā)(Java的Copy On Write容器)、高可用HA軟件中廣泛使用。


*Unix

在傳統(tǒng)的Unix環(huán)境下,有兩個基本的操作用于創(chuàng)建和修改進(jìn)程:

  • 函數(shù)fork( )用來創(chuàng)建一個新的進(jìn)程,該進(jìn)程幾乎是當(dāng)前進(jìn)程的一個完全拷貝

  • 函數(shù)族exec( )用來啟動另外的進(jìn)程以取代當(dāng)前運(yùn)行的進(jìn)程(函數(shù)族exec( )是一組函數(shù)的統(tǒng)稱, 它包括了execl()、execlp()、execv()、execle()、execve()、execvp()等)

fork

fork是類Unix操作系統(tǒng)上創(chuàng)建進(jìn)程的主要方法,fork用于創(chuàng)建子進(jìn)程。

新的進(jìn)程要通過老的進(jìn)程復(fù)制自身得到,Linux下init進(jìn)程是所有進(jìn)程的父 。 Linux的進(jìn)程都通過init進(jìn)程或init的子進(jìn)程fork(vfork)出來的

#include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函數(shù)返回的值 int count=0;// 調(diào)用fork,創(chuàng)建出子進(jìn)程 fpid=fork();// 所以下面的代碼有兩個進(jìn)程執(zhí)行!if (fpid < 0) printf("創(chuàng)建進(jìn)程失敗!/n"); else if (fpid == 0) { printf("我是子進(jìn)程,由父進(jìn)程fork出來/n"); count++; } else { printf("我是父進(jìn)程/n"); count++; } printf("統(tǒng)計(jì)結(jié)果是: %d/n",count); return 0; }

輸出結(jié)果

我是子進(jìn)程,由父進(jìn)程fork出來統(tǒng)計(jì)結(jié)果是: 1我是父進(jìn)程統(tǒng)計(jì)結(jié)果是: 1

fork 函數(shù)會有兩次返回 1) 將子進(jìn)程的PID返回給父進(jìn)程,2) 0返回給子進(jìn)程。(如果小于0,則說明創(chuàng)建子進(jìn)程失敗)。

當(dāng)前進(jìn)程調(diào)用fork(),會創(chuàng)建一個跟當(dāng)前進(jìn)程完全相同的子進(jìn)程(除了pid),所以子進(jìn)程同樣是會執(zhí)行fork()之后的代碼。

故: 父進(jìn)程在執(zhí)行if代碼塊的時候,fpid變量的值是子進(jìn)程的pid,子進(jìn)程在執(zhí)行if代碼塊的時候,fpid變量的值是0


函數(shù)族exec( )

在Linux中要使用exec函數(shù)族。系統(tǒng)調(diào)用execve()對當(dāng)前進(jìn)程進(jìn)行替換,替換者為一個指定的程序,其參數(shù)包括文件名(filename)、參數(shù)列表(argv)以及環(huán)境變量(envp)。

exec函數(shù)族不止一個,但它們大致相同,在 Linux中,它們分別是:execl,execlp,execle,execv,execve和execvp。

一個進(jìn)程一旦調(diào)用exec類函數(shù),它本身就"死亡"了,系統(tǒng)把代碼段替換成新的程序的代碼,廢棄原有的數(shù)據(jù)段和堆棧段,并為新程序分配新的數(shù)據(jù)段與堆棧段,唯一留下的,就是進(jìn)程號,也就是說,對系統(tǒng)而言,還是同一個進(jìn)程,不過已經(jīng)是另一個程序了。


為什么有了COW?

早期的 Unix 在實(shí)現(xiàn) fork 系統(tǒng)調(diào)用時,并沒有使用該技術(shù),創(chuàng)建新進(jìn)程的開銷很大。

出于效率考慮,Copy On Write 技術(shù)引入到進(jìn)程中,fork 之后的父進(jìn)程和子進(jìn)程完全共享數(shù)據(jù)段、代碼段、堆和棧等的完全副本。

Linux在使用fork()函數(shù)進(jìn)程創(chuàng)建時,傳統(tǒng)fork()的做法是系統(tǒng)把所有的資源復(fù)制給新創(chuàng)建的進(jìn)程,這種方式不僅單一,而且效率低下。因?yàn)樗截惖臄?shù)據(jù)或別的資源可能是可以共享的。現(xiàn)在Linux的fork()使用寫時拷貝頁來實(shí)現(xiàn)新進(jìn)程的創(chuàng)建,它是一種可推遲甚至避免數(shù)據(jù)拷貝的技術(shù),剛開始時內(nèi)核并不會復(fù)制整個地址空間,而是讓父子進(jìn)程共享地址空間,只有在寫時才復(fù)制地址空間,使得父子進(jìn)程都擁有獨(dú)立的地址空間,即資源的復(fù)制是在只有需要寫入時才會發(fā)生,因此而稱之為Copy on Write(COW)。

在此之前都是以讀的方式去和父進(jìn)程共享資源,這樣,在頁根本不會被寫入的場景下,fork()立即執(zhí)行exec(),無需對地址空間進(jìn)行復(fù)制,fork()的實(shí)際開銷就是復(fù)制父進(jìn)程的一個頁表和為子進(jìn)程創(chuàng)建一個進(jìn)程描述符,也就是說只有當(dāng)進(jìn)程空間中各段的內(nèi)存內(nèi)容發(fā)生變化時,父進(jìn)程才將其內(nèi)容復(fù)制一份傳給子進(jìn)程,大大提高了效率。

通俗來說 fork創(chuàng)建出的子進(jìn)程,與父進(jìn)程共享內(nèi)存空間。 如果子進(jìn)程不對內(nèi)存空間進(jìn)行寫入操作的話,內(nèi)存空間中的數(shù)據(jù)并不會復(fù)制給子進(jìn)程,這樣創(chuàng)建子進(jìn)程的速度就很快 ,因?yàn)椴挥脧?fù)制,直接引用父進(jìn)程的物理空間 ,并且如果在fork函數(shù)返回之后,子進(jìn)程第一時間exec一個新的可執(zhí)行映像,那么也不會浪費(fèi)時間和內(nèi)存空間了 。


COW 原理

fork()之后,kernel把父進(jìn)程中所有的內(nèi)存頁的權(quán)限都設(shè)為read-only,然后子進(jìn)程的地址空間指向父進(jìn)程。當(dāng)父子進(jìn)程都只讀內(nèi)存時,相安無事。當(dāng)其中某個進(jìn)程寫內(nèi)存時,CPU硬件檢測到內(nèi)存頁是read-only的,于是觸發(fā)頁異常中斷(page-fault),陷入kernel的一個中斷例程。中斷例程中,kernel就會把觸發(fā)的異常的頁復(fù)制一份,于是父子進(jìn)程各自持有獨(dú)立的一份。


COW的優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

  • COW技術(shù)可減少分配和復(fù)制大量資源時帶來的瞬間延時。
  • COW技術(shù)可減少不必要的資源分配。比如fork進(jìn)程時,并不是所有的頁面都需要復(fù)制,父進(jìn)程的代碼段和只讀數(shù)據(jù)段都不被允許修改,所以無需復(fù)制。

缺點(diǎn)

  • 如果在fork()之后,父子進(jìn)程都還需要繼續(xù)進(jìn)行寫操作,那么會產(chǎn)生大量的分頁錯誤(頁異常中斷page-fault),這樣就得不償失。

小結(jié)

fork出的子進(jìn)程共享父進(jìn)程的物理空間,當(dāng)父子進(jìn)程有內(nèi)存寫入操作時,read-only內(nèi)存頁發(fā)生中斷,將觸發(fā)的異常的內(nèi)存頁復(fù)制一份(其余的頁還是共享父進(jìn)程的)。

fork出的子進(jìn)程功能實(shí)現(xiàn)和父進(jìn)程是一樣的。如果有需要, 會調(diào)用exec()把當(dāng)前進(jìn)程映像替換成新的進(jìn)程文件,完成自定義的功能。


參考:
維基百科-Copy-on-write
COW奶牛!Copy On Write機(jī)制了解一下


搞定Linux核心技術(shù)

總結(jié)

以上是生活随笔為你收集整理的Linux-Copy On Write写时复制机制初探的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。