Linux 寫時複製機制原理

在 Linux 系統中,調用 fork 系統調用創建子進程時,並不會把父進程所有佔用的內存頁複製一份,而是與父進程共用相同的內存頁,而當子進程或者父進程對內存頁進行修改時纔會進行復制 —— 這就是著名的 寫時複製 機制。

下面我們將分析 Linux 寫時複製(Copy On Write) 機制的原理。

虛擬內存與物理內存
進程的內存可分爲 虛擬內存 和 物理內存。

物理內存:就是電腦安裝的內存條,如果電腦安裝了2GB的內存條,那麼系統就用於 0 ~ 2GB 的物理內存空間。

虛擬內存:虛擬內存是使用軟件虛擬的,在 32 位操作系統中,每個進程都獨佔 4GB 的虛擬內存空間。

應用程序使用的是 虛擬內存,比如 C 語言取地址操作符號 & 所得到的地址就是 虛擬內存地址。而 虛擬內存地址 需要映射到 物理內存地址 才能使用,如果使用沒有映射的 虛擬內存地址,將會導致 缺頁異常。

虛擬內存地址 映射到 物理內存地址 如下圖所示:

如上圖所示,進程A與進程B的相同 虛擬內存地址 映射到不同的 物理內存地址,這就是不同進程的相同虛擬內存地址互不影響的原因。

寫時複製原理
前面介紹了 虛擬內存 與 物理內存 的概念,接下來將會介紹 Linux 寫時複製 的原理。

前面說過,虛擬內存 需要與 物理內存 進行映射才能使用,如果不同進程的 虛擬內存地址 映射到相同的 物理內存地址,那麼就實現了共享內存的機制。如下圖所示:

由於進程A的 虛擬內存M 與進程B的 虛擬內存M' 映射到相同的 物理內存G,所以當修改進程A 虛擬內存M 的數據時,進程B 虛擬內存M' 的數據也會跟着改變。

Linux 爲了加速創建子進程過程與節省內存使用的原因,實現了 寫時複製 的機制。

寫時複製 的原理大概如下:

創建子進程時,將父進程的 虛擬內存 與 物理內存 映射關係複製到子進程中,並將內存設置爲只讀(爲什麼要設置爲只讀?)。

當子進程或者父進程對內存數據進行修改時,便會觸發 寫時複製 機制:將原來的內存頁複製一份新的,並重新設置其內存映射關係,將父子進程的內存讀寫權限設置爲可讀寫。

寫時複製 過程如下圖所示:

從上圖可知,當創建子進程時,父子進程指向相同的 物理內存,而不是將父進程所佔用的 物理內存 複製一份。這樣做的好處有兩個:

  • 加速創建子進程的速度。
  • 減少進程對物理內存的使用。

但這個時候只能對內存進行讀操作,如果父進程或子進程對內存進行寫操作,那麼將會觸發 缺頁異常,而在 缺頁異常 處理中會對物理內存進行復制,並且重新映射其內存映射關係。

複製並重新映射到新的物理內存後,父子進程的虛擬內存就映射到不同的物理內存上,這時父子進程都可以對內存進行寫操作而互不影響,所以需要把父子進程的內存讀寫權限設置爲可讀寫。

總結
本篇文章主要介紹了 Linux 寫時複製 的原理,寫時複製 是 Linux 創建子進程高效的關鍵所在,而且還能節省對物理內存使用。我們將在下一篇文章中對 寫時複製 的實現進行詳細的分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章