Windows記憶體原理與記憶體管理

2021-09-22 22:39:48 字數 3751 閱讀 6138

windows為每個程序分配了4gb的虛擬位址空間,讓每個程序都認為自己擁有4gb的記憶體空間,4gb怎麼來的? 32位 cpu可以取位址的空間為2的32次方,就是4gb(正如16位cpu有20根定址線所有擁有2的20次方的定址空間一樣)

當我們在windows中雙擊乙個應用程式圖示後,系統為該應用程式建立乙個程序,windows使得每個程序都擁有2gb的位址空間,這2gb位址空間用於程式存放**,資料,堆疊,自由儲存區(堆),另外2gb用於共享系統使用

前面的這些位址並不是物理記憶體中的位址,而是該程序空間中的虛擬位址 

虛擬空間只是windows為該程序分配的乙個虛擬的位址空間,只有當其和物理記憶體相關聯後才有意義 

記憶體的分頁 

每個實體地址對應乙個虛擬位址?1gb那頁表該有多長,所以將記憶體分頁管理,4k為一頁,即4k就是乙個最小單位。虛擬位址到實體地址的對映見圖,中間的那個就是頁表了。

如何對映? 

程序被建立時會建立乙個 虛擬內從到物理記憶體的對映表--------頁表,根據頁表可以將虛擬記憶體和物理記憶體關聯起來

-----------------------------------------頁表如何工作,怎麼將虛擬位址關聯實體地址----------------------------------

虛擬記憶體是什麼? 

就是把磁碟拿來當記憶體用,這是以前買電腦時的想法。 

所以就一直都想不明白乙個問題:要真是這樣,那記憶體分個什麼1gb,2gb,4gb,大家都買個1m的記憶體條,然後把自己磁碟拿來當記憶體用多好,比2gb,4gb不知道要大多少。 

其實這個說法有一點擦邊球的味道,虛擬記憶體是一些系統頁檔案,存放在磁碟上,每個系統頁檔案大小也為4k,物理記憶體也被分頁,每個頁大小也為4k,這樣虛擬頁檔案和物理記憶體頁就可以對應,實際上虛擬記憶體就是用於物理記憶體的臨時存放的磁碟空間。 

頁檔案就是記憶體頁,物理記憶體中每頁叫物理頁,磁碟上的頁檔案叫虛擬頁,物理頁+虛擬頁就是系統所以使用的頁檔案的總和。還有映像頁檔案和對映頁檔案,映像頁檔案就是拿程式本身當頁檔案使用(而不是用系統的頁檔案),對映頁檔案就是使用磁碟上的檔案(非系統頁檔案)來當頁檔案使用(這主要用於讀取檔案)。

虛擬位址頁的狀態: 

空閒:該區域沒有被所使用,也沒有被預定,沒有和物理記憶體管理 

私有:該區域雖然沒有被使用,但是已經被申請(預定了),別人無法使用它。同樣也沒和物理記憶體關聯 

提交:該區域已經和物理記憶體管理,可以使用了

虛擬記憶體和物理記憶體的管理(windows記憶體管理的核心) 

windows是多工的系統,在每個程序建立時,系統為每個程序也建立了乙個頁表,用於虛擬位址到實體地址的轉換。比如現在程式在執行程序a,使用者切換到了另外乙個程序b,則系統會將程序a在記憶體中的資料存放到頁檔案中,並更新程序a的頁表(使虛擬位址和頁檔案形成對映)。然後讀取程序b的頁表,根據頁表判斷程序b的資料是在記憶體中還是在頁檔案中(通過頁檔案的型別來判斷),如果在記憶體中就直接讀取,如果在頁面檔案中,就將頁面檔案內容讀入物理記憶體,然後更新頁表(使虛擬位址和物理記憶體形成對映)。這樣一看,虛擬記憶體實際上就是冒牌的物理記憶體了吧。 

程式的執行 

乙個pe檔案有資料區,**區,堆疊區(由系統分配,用於管理區域性變數),使用od載入乙個程式就可以知道這些都是以二進位制的形式儲存在檔案中。 

程式剛執行的時候,系統不直接將整個程式載入到物理記憶體中,也不將其載入到頁檔案中,而是以程式檔案本身作為頁檔案形成對映(虛擬位址到頁檔案的對映),建立頁表,然後隨著程式的執行通過頁表來將其虛擬位址轉換成實體地址(將頁檔案讀入記憶體),然後在讀取記憶體中的指令或資料。當程序被切換時,將記憶體內容儲存到頁檔案,更新頁表,如此往復,實現多工操作。

可以知道,程式的**段,資料段,堆疊區(系統分配)這些虛擬位址區域已經是對映狀態,即有相應的物理記憶體與之對應。系統為每個程序提供了2g的自己的虛擬位址空間,剩下的虛擬位址空間幹什麼用? 

剩下的虛擬位址空間就是給程式執行時動態分配記憶體使用。c++中 new的功能就是動態分配位址空間: 

申請記憶體的最小單位是區域,每個區域為cpu粒度大小,即64k,每次申請的記憶體都必須是64k的整數倍,c++ new功能申請乙個區域,保留該區域,然後提交需要的頁,其他的保留。

char *address=new char[1024];   //分配1k的記憶體 

這條語句首先申請乙個區域的位址空間,表示這個區域已經被預定了,這就是上述區域狀態中的私有狀態,雖然預定了,但是還沒有和物理記憶體關聯起來,所以程式也無法使用該記憶體,然後程式將這1k的記憶體提交,就是對映到了記憶體當中,區域的狀態就變成了對映狀態,這樣程式就可以使用這1k的記憶體了,而剩下的頁仍然為保留狀態。那當程序被切換時,這1k的程序存放在哪呢?程式本身的頁檔案已經被 **,全域性資料,堆疊這些所使用了,所以系統會為自由儲存區分配的記憶體分配新的頁檔案來做虛擬記憶體。

區域性變數的定義是由系統分配的,它將區域性變數分配到堆疊區,因為堆疊區已經映**,所以不用在對映,故不用使用新的頁檔案了。堆疊區的大小為1m左右,如果分配的區域性變數超過1m會產生堆疊溢位。

可以看到,系統的單個頁檔案大小為4k,程式自己的虛擬空間位址從00010000到7ffeffff差不多是2g 

動態分配乙個500m的記憶體後,物理記憶體,頁檔案,可用的虛擬位址空間都減少了500m

查詢記憶體狀態使用virtualquery(address[n],&membaseinf,sizeof(memory_basic_information)) 

定義3個變數 

char stack[20*1024];          //存在堆疊中,堆疊在程式啟動時已經被映像到記憶體中了 

char* dynamic=new char[64*1024];       //動態分配乙個70k的記憶體 

char* dynamic2=new char[1024];          //動態分配乙個1k的記憶體

申請乙個記憶體空間的過程 

首先申請乙個虛擬位址空間區域,然後提交申請的記憶體空間大小的頁(將其和頁檔案關聯)。其他的位址空間保留。 

第一條指令分配了乙個字元陣列的區域性變數,該變數分配在堆疊中,由系統分配,所以其區域為程式的靜態儲存區,即在程式啟動時候這個區域的所有虛擬位址就和程式檔案本身映像了,所以區域性變數的區域基位址都是一樣的,那為什麼它的頁面檔案型別是頁檔案呢?不應該是exe映像麼?因為現在檔案在記憶體中,所有是物理頁,就是頁檔案。 

第二條指令動態分配了一塊大小為1k的記憶體區域,這塊記憶體分配在自由儲存區,它所在的區域是在堆中申請的乙個區域,第三條指令在堆中分配了乙個70k左右的記憶體,因為他們是在堆中分配的,所以這2個變數的區域基位址是不一樣的。

分配的區域有多大? 

第三條指令分配了乙個70k左右的記憶體,它會向系統申請多大的區域呢?由區域大小為64k的整數倍知該區域至少為128k,查詢這70k之後的虛擬位址的狀態

可以看到該位址所在的區域和dynamic是一樣的,它的基位址為594000,在那70k之後,這之後的區域的狀態為保留,說明系統保留了剩下的區域,這剩下的區域有966656,就是966k左右的大小,那整個區域的大小就是(0x14000)81920+966656。

window記憶體管理與記憶體原理

windows為每個程序分配了4gb的虛擬位址空間,讓每個程序都認為自己擁有4gb的記憶體空間,4gb怎麼來的?32位 cpu可以取位址的空間為2的32次方,就是4gb 正如16位cpu有20根定址線所有擁有2的20次方的定址空間一樣 當我們在windows中雙擊乙個應用程式圖示後,系統為該應用程式...

ios 記憶體管理,objective c記憶體管理

整理下筆記,如有不準備的地方,望指正。雖然現在蘋果已經大力推崇arc自動記憶體管理,記憶體管理已經不需要我們手動處理,作為新手,還是要了解一下。首先如果是5.x以上版本的xcode,xcode建立新project的時候預設是適用arc的,如果想自己管理記憶體 可以在edit scheme中設定obj...

mecached記憶體管理與原理

許多web應用程式都將資料儲存到rdbms中,應用伺服器從中讀取資料並在瀏覽器中顯示。但隨著資料量的增大,訪問的集中,就會出現rebms的負擔加重,資料庫響應惡化,顯示延遲等重大影響。memcached是高效能的分布式記憶體快取伺服器。一般的使用目的是通過快取資料庫查詢結果,減少資料庫的訪問次數,以...