對進程空間的認識

(爲何32位的機器的進程地址空間爲4GB)html

在進入正題前先來談談操做系統內存管理機制的發展歷程,瞭解這些有利於咱們更好的理解目前操做系統的內存管理機制。windows

1、早期的內存分配機制數據結構

在 早期的計算機中,要運行一個程序,會把這些程序全都裝入內存,程序都是直接運行在內存上的,也就是說程序中訪問的內存地址都是實際的物理內存地址。當計算機同時運行多個程序時,必須保證這些程序用到的內存總量要小於計算機實際物理內存的大小。那當程序同時運行多個程序時,操做系統是如何爲這些程序分配內存 的呢?下面經過實例來講明當時的內存分配方法:函數

某臺計算機總的內存大小是 128M ,如今同時運行兩個程序 A 和 B , A 需佔用內存 10M , B 需佔用內存 110 。計算機在給程序分配內存時會採起這樣的方法:先將內存中的前 10M 分配給程序 A ,接着再從內存中剩餘的 118M 中劃分出 110M 分配給程序 B 。這種分配方法能夠保證程序 A 和程序 B 都能運行,可是這種簡單的內存分配策略問題不少。spa

 

圖一 早期的內存分配方法操作系統

問題 1 :進程地址空間不隔離。因爲程序都是直接訪問物理內存,因此惡意程序能夠隨意修改別的進程的內存數據,以達到破壞的目的。有些非惡意的,可是有 bug 的程序也可能不當心修改了其它程序的內存數據,就會致使其它程序的運行出現異常。這種狀況對用戶來講是沒法容忍的,由於用戶但願使用計算機的時候,其中一個任務失敗了,至少不能影響其它的任務。線程

問題 2 :內存使用效率低。在 A 和 B 都運行的狀況下,若是用戶又運行了程序 C ,而程序 C 須要 20M 大小的內存才能運行,而此時系統只剩下 8M 的空間可供使用,因此此時系統必須在已運行的程序中選擇一個將該程序的數據暫時拷貝到硬盤上,釋放出部分空間來供程序 C 使用,而後再將程序 C 的數據所有裝入內存中運行。能夠想象獲得,在這個過程當中,有大量的數據在裝入裝出,致使效率十分低下。指針

問題 3 :程序運行的地址不肯定。當內存中的剩餘空間能夠知足程序 C 的要求後,操做系統會在剩餘空間中隨機分配一段連續的 20M 大小的空間給程序 C 使用,由於是隨機分配的,因此程序運行的地址是不肯定的。htm

2、分段對象

爲 瞭解決上述問題,人們想到了一種變通的方法,就是增長一箇中間層,利用一種間接的地址訪問方法訪問物理內存。按照這種方法,程序中訪問的內存地址再也不是實際的物理內存地址,而是一個虛擬地址,而後由操做系統將這個虛擬地址映射到適當的物理內存地址上。這樣,只要操做系統處理好虛擬地址到物理內存地址的映 射,就能夠保證不一樣的程序最終訪問的內存地址位於不一樣的區域,彼此沒有重疊,就能夠達到內存地址空間隔離的效果。

當建立一個進程時,操做系統會爲該進程分配一個 4GB 大小的虛擬 進程地址空間。之因此是 4GB ,是由於在 32 位的操做系統中,一個指針長度是 4 字節,而 4 字節指針的尋址能力是從 0x00000000~0xFFFFFFFF ,最大值 0xFFFFFFFF 表示的即爲 4GB 大小的容量。與虛擬地址空間相對的,還有一個物理地址空間,這個地址空間對應的是真實的物理內存。若是你的計算機上安裝了 512M 大小的內存,那麼這個物理地址空間表示的範圍是 0x00000000~0x1FFFFFFF 。當操做系統作虛擬地址到物理地址映射時,只能映射到這一範圍,操做系統也只會映射到這一範圍。當進程建立時,每一個進程都會有一個本身的 4GB 虛擬地址空間。要注意的是這個 4GB 的地址空間是「虛擬」的,並非真實存在的,並且每一個進程只能訪問本身虛擬地址空間中的數據,沒法訪問別的進程中的數據,經過這種方法實現了進程間的地址隔離。那是否是這 4GB 的虛擬地址空間應用程序能夠隨意使用呢?很遺憾,在 Windows 系統下,這個虛擬地址空間被分紅了 4 部分: NULL 指針區、用戶區、 64KB 禁入區、內核區。應用程序能使用的只是用戶區而已,大約 2GB 左右 ( 最大能夠調整到 3GB) 。內核區爲 2GB ,內核區保存的是系統線程調度、內存管理、設備驅動等數據,這部分數據供全部的進程共享,但應用程序是不能直接訪問的。

      人 們之因此要建立一個虛擬地址空間,目的是爲了解決進程地址空間隔離的問題。但程序要想執行,必須運行在真實的內存上,因此,必須在虛擬地址與物理地址間創建一種映射關係。這樣,經過映射機制,當程序訪問虛擬地址空間上的某個地址值時,就至關於訪問了物理地址空間中的另外一個值。人們想到了一種分段 (Sagmentation) 的方法,它的思想是在虛擬地址空間和物理地址空間之間作一一映射。好比說虛擬地址空間中某個 10M 大小的空間映射到物理地址空間中某個 10M 大小的空間。這種思想理解起來並不難,操做系統保證不一樣進程的地址空間被映射到物理地址空間中不一樣的區域上,這樣每一個進程最終訪問到的

物理地址空間都是彼此分開的。經過這種方式,就實現了進程間的地址隔離。仍是以實例說明,假設有兩個進程 A 和 B ,進程 A 所需內存大小爲 10M ,其虛擬地址空間分佈在 0x00000000 到 0x00A00000 ,進程 B 所需內存爲 100M ,其虛擬地址空間分佈爲 0x00000000 到 0x06400000 。那麼按照分段的映射方法,進程 A 在物理內存上映射區域爲 0x00100000 到 0x00B00000 ,,進程 B 在物理內存上映射區域爲 0x00C00000 到 0x07000000 。因而進程 A 和進程 B 分別被映射到了不一樣的內存區間,彼此互不重疊,實現了地址隔離。從應用程序的角度看來,進程 A 的地址空間就是分佈在 0x00000000 到 0x00A00000 ,在作開發時,開發人員只需訪問這段區間上的地址便可。應用程序並不關心進程 A 究竟被映射到物理內存的那塊區域上了,因此程序的運行地址也就是至關於說是肯定的了。 圖二顯示的是分段方式

的內存映射方法。 

 

圖二 分段方式的內存映射方法

      這 種分段的映射方法雖然解決了上述中的問題一和問題三,但並沒能解決問題二,即內存的使用效率問題。在分段的映射方法中,每次換入換出內存的都是整個程序,這樣會形成大量的磁盤訪問操做,致使效率低下。因此這種映射方法仍是稍顯粗糙,粒度比較大。實際上,程序的運行有局部性特色,在某個時間段內,程序只是訪 問程序的一小部分數據,也就是說,程序的大部分數據在一個時間段內都不會被用到。基於這種狀況,人們想到了粒度更小的內存分割和映射方法,這種方法就是分頁 (Paging) 。  

3、分頁

分頁的基本方法是,將地址空間分紅許多的頁。每頁的大小由 CPU 決定,而後由操做系統選擇頁的大小。目前 Inter 系列的 CPU 支持 4KB 或 4MB 的頁大小,而 PC 上目前都選擇使用 4KB 。按這種選擇, 4GB 虛擬地址空間共能夠分紅 1048576 個頁, 512M 的物理內存能夠分爲 131072 個頁。顯然虛擬空間的頁數要比物理空間的頁數多得多。

在 分段的方法中,每次程序運行時老是把程序所有裝入內存,而分頁的方法則有所不一樣。分頁的思想是程序運行時用到哪頁就爲哪頁分配內存,沒用到的頁暫時保留在硬盤上。當用到這些頁時再在物理地址空間中爲這些頁分配內存,而後創建虛擬地址空間中的頁和剛分配的物理內存頁間的映射。

下面經過介紹一個可執行文件的裝載過程來講明分頁機制的實現方法。一個可執行文件 (PE 文件 ) 其實就是一些編譯連接好的數據和指令的集合,它也會被分紅不少頁,在 PE 文件執行的過程當中,它往內存中裝載的單位就是頁。當一個 PE 文件被執行時,操做系統會先爲該程序建立一個 4GB 的進程虛擬地址空間。前面介紹過,虛擬地址空間只是一箇中間層而已,它的功能是利用一種映射機制將虛擬地址空間映射到物理地址空間,因此,建立 4GB 虛擬地址空間其實並非要真的建立空間,只是要建立那種映射機制所須要的數據結構而已,這種數據結構就是頁目和頁表。

當建立完虛擬地址空間所須要的數據結構後,進程開始讀取 PE 文件的第一頁。在 PE 文件的第一頁包含了 PE 文件頭和段表等信息,進程根據文件頭和段表等信息,將 PE 文件中全部的段一一映射到虛擬地址空間中相應的頁 (PE 文件中的段的長度都是頁長的整數倍 ) 。這時 PE 文件的真正指令和數據尚未被裝入內存中,操做系統只是根據 PE 文件的頭部等信息創建了 PE 文件和進程虛擬地址空間中頁的映射關係而已。當 CPU 要訪問程序中用到的某個虛擬地址時,當 CPU 發現該地址並無相相關聯的物理地址時, CPU 認爲該虛擬地址所在的頁面是個空頁面, CPU 會認爲這是個頁錯誤 (Page Fault) , CPU 也就知道了操做系統還未給該 PE 頁面分配內存, CPU 會將控制權交還給操做系統。操做系統因而爲該 PE 頁面在物理空間中分配一個頁面,而後再將這個物理頁面與虛擬空間中的虛擬頁面映射起來,而後將控制權再還給進程,進程從剛纔發生頁錯誤的位置從新開始執行。因爲此時已爲 PE 文件的那個頁面分配了內存,因此就不會發生頁錯誤了。隨着程序的執行,頁錯誤會不斷地產生,操做系統也會爲進程分配相應的物理頁面來知足進程執行的需求。

分頁方法的核心思想就是當可執行文件執行到第 x 頁時,就爲第 x 頁分配一個內存頁 y ,而後再將這個內存頁添加到進程虛擬地址空間的映射表中 , 這個映射表就至關於一個 y=f(x) 函數。應用程序經過這個映射表就能夠訪問到 x 頁關聯的 y 頁了。

 

總結:

32位的CPU 的尋址空間是4GB , 因此虛擬內存的最大值爲4GB , 而windows 操做系統把這4GB 分紅2 部分, 即2G 的用戶空間和2G 的系統空間, 系統空間是各個進程所共享的, 他存放的是操做系統及一些內核對象等, 而用戶空間是分配給各個進程使用的, 用戶空間包括用: 程序代碼和數據, 堆, 共享庫, 棧。

 

 

reference

相關文章
相關標籤/搜索