1. 程式人生 > >內存分配(malloc,new,VirtualAlloc,HeapAlloc,GlobalAlloc,LocalAlloc)區別與註意

內存分配(malloc,new,VirtualAlloc,HeapAlloc,GlobalAlloc,LocalAlloc)區別與註意

實例 item 自己的 變量 c++ 完全 add pro ansi

malloc()
頭文件:#include <malloc.h> 或 #include <alloc.h> (註意:alloc.h 與 malloc.h 的內容是完全一致的。)
功能:分配長度為num_bytes字節的內存塊
說明:如果分配成功則返回指向被分配內存的指針,否則返回空指針NULL。
當內存不再使用時,應使用free()函數將內存塊釋放。

C運行庫中的動態內存分配函數,主要用於ANSI C(C語言的標準)程序中,是標準庫函數。WINDOWS程序基本不再使用這種方法進行內存操作,因為它比WINDOWS內存分配函數少了一些特性,如整理內存

註:
一般 malloc 的實現並不是從系統的堆中分配的, 而是從編譯器連接的運行庫自己管理的堆中, 在 Win32 平臺上的開發工具的編譯結果中, 通常是用 HeapCreate 創建一個堆, 用 HeapAlloc 和 HeapRealloc 維護堆的空間增長, 在最後用 HeapDestroy 刪除堆. 而在用 malloc 分配, 用 free 釋放時則由運行庫的代碼負責從這個堆中分配空間和向這個堆中歸還空間, 並維護這個堆中的數據結構. 由於 malloc 堆的管理是由運行庫自己管理的, 所在當我們使用靜態運行庫時, 如果在一個 DLL 中用 malloc 分配了內存而在另一個 DLL 中用 free 去釋放它, 通常都會產生問題. 這是因為每個DLL都連接了一份運行庫的代碼, 從而也都有一個自己的局部堆, 而在用 free 釋放時它會假設這塊內存是在自己的堆中分配的, 從而導致錯誤. 而通過 GlobalAlloc 和 LocalAlloc 分配的內存不存在這個問題.

new()
標準C++一般使用new語句分配動態的內存空間,

需要申請數組時,可以直接使用new int[8]這樣的方式,釋放該方法申請的內存空間使用對應的delete語句,需要釋放的內存空間為一個數組,則使用delete [] ary;

要訪問new所開辟的結構體空間,無法直接通過變量名進行,只能通過賦值的指針進行訪問.

new在內部調用malloc來分配內存,delete在內部調用free來釋放內存。

 

HeapALloc()

LPVOID HeapAlloc(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes);

windows系統的函數


HeapALloc是從堆上分配一塊內存,且如果沒有連續的空間能滿足分配的大小,會導致分配失敗,該分配方法是從一指定地址開始分配,而不像GloabalAlloc是從全局堆上分配,這個有可能是全局,也有可能是局部

HeapDestroy 刪除堆

VirtualAlloc()
PVOID VirtualAlloc(PVOID pvAddress, SIZE_T dwSize, DWORD fdwAllocationType, DWORD fdwProtect)
VirtualAlloc是Windows提供的API,通常用來分配大塊的內存。例如如果想在進程A和進程B之間通過共享內存的方式實現通信,可以使用該函數(這也是較常用的情況)。不要用該函數實現通常情況的內存分配。該函數的一個重要特性是可以預定指定地址和大小的虛擬內存空間。例如,希望在進程的地址空間中第50MB的地方分配內存,那麽將參數 50*1024*`1024 = 52428800 傳遞給pvAddress,將需要的內存大小傳遞給dwSize。如果系統有足夠大的閑置區域能滿足請求,則系統會將該塊區域預訂下來並返回預訂內存的基地址,否則返回NULL。


使用VirtualAlloc分配的內存需要使用VirtualFree來釋放。

VirtualAlloc
BufferData = (uint8_t*)VirtualAlloc(NULL, BufferLength, MEM_COMMIT, PAGE_READWRITE);
if (BufferData!=NULL)
{
VirtualFree(BufferData,0,MEM_RELEASE);
BufferData = NULL;
}
大量的數據緩沖區,動態分配內存的空間。使用VirtualAlloc函數來分配內存的速度要比全局內存要快。

GlobalAlloc() LocalAlloc()

HLOCAL LocalAlloc( UINT uFlags, SIZE_T uBytes );
GlobalAlloc( UINT uFlags, SIZE_T uBytes );
在16位Windows中是有區別的,因為在16位windows用一個全局堆和局部堆來管理內存,每一個應用程序或dll裝入內存時,代碼段被裝入全局 堆,而系統又為每個實例從全局堆中分配了一個64kb的數據段作為該實例的局部堆,用來存放應用程序的堆棧和所有全局或靜態變量。 LocalAlloc用於在局部堆 GlobalAlloc用於全局堆中分配內存。
由於每個進程的局部堆很小,所以在局部堆中分配內存會受到空間的限制。但這個堆是每個進程私有的,相對而言分配數據較安全,數據訪問出錯不至於影響到整個系統。
而在全局堆中分配的內存是為各個進程共享的,每個進程只要擁有這個內存塊的句柄都可以訪問這塊內存,但是每個全局內存空間需要額外的內存開銷,造成分配浪費。而且一旦發生嚴重錯誤,可能會影響到整個系統的穩定。
不過在Win32中,每個進程都只擁有一個省缺的私有堆,它只能被當前進程訪問。應用程序也不可能直接訪問系統內存。所以在Win32中全局堆和局部堆都 指向進程的省缺堆。用LocalAlloc/GlobalAlloc分配內存沒有任何區別。甚至LocalAlloc分配的內存可以被 GlobalFree釋放掉。

它們之間的區別主要有以下幾點:
1、GlobalAlloc()函數在程序的堆中分配一定的內存,是Win16的函數,對應於系統的全局棧,而在Win32中全局棧和局部堆的區別已經不存在了,因此不推薦在Win32中使用該函數。
2、malloc()是標準庫函數,而new則是運算符,它們都可以用於申請動態內存。
3、new()實際上調用的是malloc()函數。
4、new運算符除了分配內存,還可以調用構造函數,但是malloc()函數只負責分配內存。
5、對於非內部數據類型的對象而言,只使用malloc()函數將無法滿足動態對象的要求,因為malloc()函數不能完成執行構造函數的任務。
6、malloc(); 和 HeapAlloc(); 都是從堆中分配相應的內存,不同的是一個是c run time的函數,一個是windows系統的函數, 對於windows程序來說,使用HeapAlloc();會比malloc();效率稍稍高一些。

錯誤可能
1..內存分配成功卻沒有初始化
2.越界
3忘記釋放內存
4釋放內存後繼續使用

註意 數據結構設計
申請內存後判斷指針是否為空
釋放後將指針置為空
動態申請與釋放一定要配對,以防內存泄漏
不要反悔指向“棧內存”的指針或引用

未完,之後會加入一些實例化代碼

內存分配(malloc,new,VirtualAlloc,HeapAlloc,GlobalAlloc,LocalAlloc)區別與註意