1. 程式人生 > >Windows系統上的VirtualAlloc, HeapAlloc和malloc,new的區別

Windows系統上的VirtualAlloc, HeapAlloc和malloc,new的區別

轉載自:http://blog.csdn.net/zj510/article/details/39400087

(1) VirtualAlloc

PVOID VirtualAlloc(PVOID pvAddress, SIZE_T dwSize, DWORD fdwAllocationType, DWORD fdwProtect)

VirtualAlloc是Windows提供的API,通常用來分配大塊的記憶體。不要用該函式實現通常情況的記憶體分配。該函式的一個重要特性是可以預定指定地址和大小的虛擬記憶體空間。例如,希望在程序的地址空間中第50MB的地方分配記憶體,那麼將引數 50*1024*`1024 = 52428800 傳遞給pvAddress,將需要的記憶體大小傳遞給dwSize。如果系統有足夠大的閒置區域能滿足請求,則系統會將該塊區域預訂下來並返回預訂記憶體的基地址,否則返回NULL。

使用VirtualAlloc分配的記憶體需要使用VirtualFree來釋放.

(2) HeapAlloc

HeapAlloc是Windows提供的API,在程序初始化的時候,系統會在程序的地址空間中建立1M大小的堆,稱為預設堆(Default Heap),該大小為預設值,可以通過/HEAP聯結器開關進行修改。使用者也可以通過HeapCreate建立額外的堆,堆的使用可以更有效的進行記憶體管理,避免執行緒同步的開銷以及快速的釋放記憶體等。HeapAlloc用於從堆上分配一個記憶體塊,如果分配成功則返回記憶體塊的地址。HeapAlloc內部會根據請求的大小以及堆的大小來決定具體的實現,例如在需要大的記憶體空間時,會自動呼叫VirtualAlloc函式分配空間。該函式通常用來分配一般大小的記憶體空間,一些Windows API可能會要求使用該函式進行記憶體分配並傳遞給API引數。注意,在分配大的記憶體塊時(例如1M或者更多)最好避免使用堆函式,建議使用VirtualAlloc。

使用HeapFree釋放由HeapAlloc的分配的記憶體.

(3) malloc

C語言的記憶體分配函式,用於分配一般的記憶體空間,該函式分配的記憶體不會自動進行初始化。如果使用C語言程式設計,使用該函式。在Visual C++ 中,malloc函式會呼叫HeapAlloc函式。

malloc分配的記憶體由free函式釋放。

(4) new

C++語言的實現方式,在Visual C++ 中,通過呼叫HeapAlloc實現記憶體分配,如果使用C++程式設計,建議使用new進行一般記憶體的分配。系統根據呼叫的方式決定是否對物件進行初始化。

注意: new 在C++中實際上是操作符而不是函式。

使用new 分配的記憶體由delete / delete[] 進行釋放。



記憶體管理有三種方式:

1. 虛擬記憶體,VirtualAlloc之類的函式

2. 堆,Heapxxx函式,malloc,new等

3. 記憶體對映檔案,Memory Mapped File

很多人都會困惑,但是看下面的圖片就會比較明白了。這個圖片從MSDN上拷來。

堆和虛擬記憶體,從上面的圖片就可以看出,其實所謂的堆,也就是在虛擬記憶體上抽象出來的。如果直接用Virtualxxx系列函式,是有一些限制的,比如每次只能分配頁大小倍數的記憶體,記憶體地址也必須對齊什麼的。新手很難用。正因為如此,才出現了堆。實際上堆Heap內部就是使用Virtual系列函式的。基本思想就是:先用VirtualAlloc分配一個比較大的記憶體,然後使用者每次申請堆記憶體的時候,從分配出來的虛擬記憶體塊上指定一塊給使用者。比如第一次分配堆記憶體從A地址開始的100個位元組,第二次分配的時候就是A+100開始。

Memory Mapped File就不太一樣了,從上面的圖可以看出MMF並沒有呼叫Virtual系列函式。它直接呼叫核心層了。

對於malloc和new,這2個並不是作業系統API,它們是語言提供的函式。在不同的系統上面有不同的實現方法,在Windows上面,new呼叫malloc,malloc呼叫堆函式(heapxxx),堆函式呼叫Virtual系列函式。在Linux上面就呼叫相應的linux API.


-------------------------

以前對虛擬記憶體一直有誤解,以為虛擬記憶體就是所謂的(頁交換檔案)其實虛擬記憶體在作業系統上的概念是:虛擬地址空間所對映的實體記憶體。所謂虛擬就是(虛擬地址的意思)

另外微軟作業系統中解釋的虛擬記憶體就是所謂的(頁交換檔案)

虛擬地址空間(預定並調撥以後)->實體地址空間(通常是磁碟,僅僅是空間對應) 

如果需要訪問一個單元的資料(比如寫入)會檢查其是否存在與隨機記憶體中(RAM)如果存在則直接訪問。

如果不存在隨機記憶體,系統會直接去檢查是否存在頁面檔案(實體地址)。如果當前隨機記憶體中有閒置的頁面,則將實體地址中的資料載入入隨機記憶體的頁面中的閒置頁面。

如果當前隨機記憶體中沒有閒置的頁面,則會釋放一個頁面(被釋放的頁面中的資料如果被修改過會將其寫入實體地址,磁碟中)。然後將需要的資料從其實體地址讀入剛被釋放的頁面(隨機記憶體中)。

特例:對於記憶體映像檔案(如exe ,dll)通常不會在頁面檔案中為其建立副本。而會直接將其虛擬地址隱射到磁碟檔案上。

當多個程序對應同一個記憶體映像檔案的磁碟檔案時,若有程序中的執行緒對其地址空間做修改(比如修改一個全域性靜態變數),由於會影響到所對應的磁碟上的檔案。此時作業系統才會在交換檔案中為其建立副本,並重新對映虛擬記憶體中對應的實體地址(磁碟)。