1. 程式人生 > >new,malloc,GlobalAlloc具體解釋

new,malloc,GlobalAlloc具體解釋

signed 註意力 註意 reg 即使 ble 而在 plain free

WINDOWS下最好的方式是用VirtualAlloc分配內存,他不是在堆,也不是棧,而是直接在進程的地址空間中保留一快內存。盡管用起來最不方便。

可是速度快,也最靈活

new,malloc,GlobalAlloc具體解釋

同樣點:都可用於申請動態內存和釋放內存

不同點:
(1)操作對象有所不同。
malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。

對於非內部數據類的對象而言。光用maloc/free無法滿足動態對象的要求。

對象在創建的同一時候要自己主動運行構造函數,對象消亡之前要自己主動運行析構函數。因為malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不可以把運行構造函數和析構函數的任務強加malloc/free。

(2)使用方法上也有所不同。


函數malloc 的原型例如以下:
void * malloc(size_t size);
用malloc 申請一塊長度為length 的整數類型的內存,程序例如以下:
int *p = (int *) malloc(sizeof(int) * length);
我們應當把註意力集中在兩個要素上:“類型轉換”和“sizeof”。
1、malloc 返回值的類型是void *。所以在調用malloc時要顯式地進行類型轉換。
2、 malloc 函數本身並不識別要申請的內存是什麽類型,它僅僅關心內存的總字節數。
函數free 的原型例如以下:
void free( void * memblock );
為什麽free 函數不象malloc 函數那樣復雜呢?這是由於指針p 的類型以及它所指的內存的容量事先都是知道的,語句free(p)能正確地釋放內存。假設p是NULL 指針,那麽free對p不管操作多少次都不會出問題。假設p不是NULL 指針,那麽free 對p連續操作兩次就會導致程序執行錯誤。


new/delete 的使用要點:
運算符new使用起來要比函數malloc簡單得多。比如:
int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];
這是由於new 內置了sizeof、類型轉換和類型安全檢查功能。對於非內部數據類型的對象而言,new在創建動態對象的同一時候完畢了初始化工作。假設對象有多個構造函數。那麽new的語句也能夠有多種形式。
假設用new 創建對象數組,那麽僅僅能使用對象的無參數構造函數。

比如
Obj *objects = new Obj[100]; // 創建100個動態對象
不能寫成
Obj *objects = new Obj[100](1); // 創建100個動態對象的同一時候賦初值1
在用delete 釋放對象數組時,留意不要丟了符號‘[]’。比如
delete []objects; // 正確的使用方法
delete objects; // 錯誤的使用方法,相當於delete objects[0],漏掉了另外99個對象。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1、new自己主動計算須要分配的空間。而malloc須要手工計算字節數
2、new是類型安全的,而malloc不是。比方:
int* p= new float[2]; // 編譯時指出錯誤
int* p= malloc(2*sizeof(float)); // 編譯時無法指出錯誤
new operator 由兩步構成。各自是 operator new和 construct
3、operator new相應於malloc。但operator new能夠重載,能夠自己定義內存分配策略,甚至不做內存分配,甚至分配到非內存設備上。而malloc無能為力
4、new將調用constructor。而malloc不能;delete將調用destructor,而free不能。
5、malloc/free要庫文件支持,new/delete則不要。


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

1、本質差別
malloc/free是C/C++語言的標準庫函數。new/delete是C++的運算符。
對於用戶自己定義的對象而言,用maloc/free無法滿足動態管理對象的要求。對象在創建的同一時候要自己主動運行構造函數,對象在消亡之前要自己主動運行析構函數。

因為malloc/free是庫函數而不是運算符。不在編譯器控制權限之內,不可以把運行構造函數和析構函數的任務強加於malloc/free。因此C++須要一個能完畢動態內存分配和初始化工作的運算符new。以及一個能完畢清理與釋放內存工作的運算符delete。

[cpp] view plaincopy

1. class Obj {

2. public:

3. Obj( ){ cout << "Initialization" << endl; }

4. ~ Obj( ) { cout << "Destroy" << endl; }

5. void Initialize( ) { cout << "Initialization" << endl; }

6. void Destroy( ) { cout << "Destroy" << endl; }

7. }obj;

8.

9. void UseMallocFree( ) {

10. Obj * a = (Obj *) malloc( sizeof ( obj ) ); // allocate memory a -> Initialize(); // initialization // …

11. a -> Destroy(); // deconstruction free(a); // release memory }

12. void UseNewDelete( void ){

13. Obj * a = new Obj;

14. // …

15. delete a;

16. }

類Obj的函數Initialize實現了構造函數的功能,函數Destroy實現了析構函數的功能。函數UseMallocFree中,因為malloc/free不能運行構造函數與析構函數,必須調用成員函數Initialize和Destroy來完畢“構造”與“析構”。所以我們不要用malloc/free來完畢動態對象的內存管理,應該用new/delete。因為內部數據類型的“對象”沒有構造與析構的過程。對它們而言malloc/free和new/delete是等價的。

2、聯系
既然new/delete的功能全然覆蓋了malloc/free,為什麽C++還保留malloc/free呢?由於C++程序常常要調用C函數,而C程序僅僅能用malloc/free管理動態內存。假設用free釋放“new創建的動態對象”,那麽該對象因無法運行析構函數而可能導致程序出錯。假設用delete釋放“malloc申請的動態內存”。理論上講程序不會出錯,可是該程序的可讀性非常差。所以new/delete、malloc/free必須配對使用。

常見的內存錯誤及對策例如以下:

1. 內存分配未成功,卻使用了它。

  經常使用解決的方法是,在使用內存之前檢查指針是否為NULL.假設是用malloc或new來申請內存。應該用if(p==NULL)或if(p!=NULL)進行防錯處理。

2.內存分配盡管成功,可是尚未初始化就引用它。

  犯這樣的錯誤主要有兩個起因:一是沒有初始化的觀念;二是誤以為內存的缺省初值全為零,導致引用初值錯誤(比如數組)。內存的缺省初值到底是什麽並沒有統一的標準,雖然有些時候為零值。

3. 忘記了釋放內存,造成內存泄露。

  含有這樣的錯誤的函數每被調用一次就丟失一塊內存。

剛開始時系統的內存充足,你看不到錯誤。終有一次程序突然死掉,系統出現提示:內存耗盡。動態內存的申請與釋放必須配對。程序中malloc與free的使用次數一定要同樣。否則肯定有錯誤(new/delete同理)。

4. 釋放了內存卻繼續使用它。

「規則1」用malloc或new申請內存之後,應該馬上檢查指針值是否為NULL.防止使用指針值為NULL的內存

  「規則2」不要忘記為數組和動態內存賦初值。防止將未被初始化的內存作為右值使用。

  「規則3」避免數組或指針的下標越界,特別要當心發生“多1”或者“少1”操作。

  「規則4」動態內存的申請與釋放必須配對,防止內存泄漏。

  「規則5」用free或delete釋放了內存之後。馬上將指針設置為NULL,防止產生“野指針”。

二。具體解釋new,malloc。GlobalAlloc

1. new使用方法:

1> 開辟單變量地址空間

1)new int; //開辟一個存放數組的存儲空間。返回一個指向該存儲空間的地址。

int*a = newint即為將一個int類型的地址賦值給整型指針a.

2)int *a = new int(5)作用同上,可是同一時候將整數賦值為5

2> 開辟數組空間

  一維: int *a = new int[100];開辟一個大小為100的整型數組空間

delete使用方法:

1> int *a = new int;

delete a。 //釋放單個int的空間

2>int *a = new int[5]。

delete [] a; //釋放int數組空間

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

  用new和delete能夠動態開辟,撤銷地址空間。在編程序時。若用完一個變量(通常是臨時存儲的數組),下次須要再用,但卻又想省去又一次初始化的功夫,能夠在每次開始使用時開辟一個空間,在用完後撤銷它。

2. malloc原型:externvoid *malloc(unsignedint num_bytes);

使用方法:#include <malloc.h>或#include<stdlib.h>功能:分配長度為num_bytes字節的內存塊說明:假設分配成功則返回指向被分配內存的指針,否則返回空指針NULL.

malloc的語法是:指針名=(數據類型*)malloc(長度)。

C。C++規定,void*類型能夠強制轉換為不論什麽其他類型的指針。

malloc()函數的工作機制malloc函數的實質體如今。它有一個將可用的內存塊連接為一個長長的列表的所謂空暇鏈表。調用malloc函數時。它沿連接表尋找一個大到足以滿足用戶請求所須要的內存塊。然後,將該內存塊一分為二(一塊的大小與用戶請求的大小相等。還有一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(假設有的話)返回到連接表上。

調用free函數時,它將用戶釋放的內存塊連接到空暇鏈上。到最後,空暇鏈會被切成非常多的小內存片段。假設這時用戶申請一個大的內存片段,那麽空暇鏈上可能沒有能夠滿足用戶要求的片段了。於是,malloc函數請求延時,並開始在空暇鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空暇塊合並成較大的內存塊。

  和new的不同從函數聲明上能夠看出。malloc和 new 至少有兩個不同: new返回指定類型的指針。而且能夠自己主動計算所須要大小。比方:int*p。p = newint; //返回類型為int*類型(整數型指針),分配大小為sizeof(int);或:int*parr;parr= new int [100];//返回類型為 int*類型(整數型指針),分配大小為sizeof(int) * 100;而 malloc則必須由我們計算要字節數,而且在返回後強行轉換為實際類型的指針。

  第二、函數的實參為 sizeof(int),用於指明一個整型數據須要的大小。假設你寫成:int* p= (int *) malloc(1);代碼也能通過編譯。但其實僅僅分配了1個字節大小的內存空間。當你往裏頭存入一個整數,就會造成的結果是後面的內存中原有數據內容所有被清空。

3. GlobalAlloc

VC中關於GlobalAlloc。GlobalLock,GlobalUnLock,GlobalFree

  調用GlobalAlloc函數分配一塊內存,該函數會返回分配的內存句柄。

  調用GlobalLock函數鎖定內存塊,該函數接受一個內存句柄作為參數。然後返回一個指向被鎖定的內存塊的指針。您能夠用該指針來讀寫內存。

  調用GlobalUnlock函數來解鎖先前被鎖定的內存。該函數使得指向內存塊的指針無效。

  調用GlobalFree函數來釋放內存塊。您必須傳給該函數一個內存句柄。

GlobalAlloc說明分配一個全局內存塊返回值Long。返回全局內存句柄。零表示失敗。會設置GetLastError參數表參數類型及說明wFlagsLong,對分配的內存類型進行定義的常數標誌,例如以下所看到的:GMEM_FIXED分配一個固定內存塊GMEM_MOVEABLE分配一個可移動內存塊GMEM_DISCARDABLE分配一個可丟棄內存塊GMEM_NOCOMPACT堆在這個函數調用期間不進行累積GMEM_NODISCARD函數調用期間不丟棄不論什麽內存塊GMEM_ZEROINIT新分配的內存塊所有初始化成零dwBytesLong。要分配的字符數

GlobalLock函數功能描寫敘述:鎖定一個全局的內存對象,返回指向該對象的第一個字節的指針函數原型:LPVOIDGlobalLock(HGLOBAL hMem )

  參數:hMem:全局內存對象的句柄。這個句柄是通過GlobalAlloc或GlobalReAlloc來得到的返回值:調用成功,返回指向該對象的第一個字節的指針調用失敗,返回NULL,能夠用GetLastError來獲得出錯信息註意:調用過GlobalLock鎖定一塊內存區後,一定要調用GlobalUnlock來解鎖

GlobalUnlock函數功能描寫敘述:解除被鎖定的全局內存對象函數原型:BOOLGlobalUnlock(HGLOBAL hMem );參數:hMem:全局內存對象的句柄返回值:非零值。指定的內存對象仍處於被鎖定狀態0,函數運行出錯,能夠用GetLastError來獲得出錯信息。假設返回NO_ERROR,則表示內存對象已經解鎖了註意: 這個函數實際上是將內存對象的鎖定計數器減一,假設計數器不為0。則表示運行過多個GlobalLock

  函數來對這個內存對象加鎖。須要相應數目的GlobalUnlock函數來解鎖。

假設通過GetLastError函數返回錯誤

  碼為ERROR_NOT_LOCKED,則表示未加鎖或已經解鎖。

  演示樣例:// Malloc memory hMem =GlobalAlloc(GMEM_MOVEABLE| GMEM_DDESHARE,nSize);//Lock memory pMem = (BYTE*)GlobalLock(hMem)。……

// Unlock memory GlobalUnlock(hMem);GlobalFree(hMem);

  三總結

  時過境遷。其現場已非出現故障時的現場了,這給調試內存問題帶來了非常大的難度。

下載Windows Debug工具, http://www.microsoft.com/whdc/devtools/debugging/default.mspx安裝後。使用當中的gflags.exe工具打開PageHeap。gflags-p /enable MainD.exe /full又一次使用VS用調試方式執行,非常快就找到了出錯位置,由於在某個靜態函數中筆誤導致

  在編寫穩定的服務器程序時,這個工具尤為實用。

參考文獻及網頁地址:

1. http://www.bccn.net/Article/kfyy/cjj/jszl/200607/4172.html

2.http://www.7880.com/Info/Article-8282a500.html C++內存管理具體解釋

5.http://www.cnblogs.com/howareyou586/archive/2008/11/06/1328353.html關於GlobalAlloc,GlobalLock,GlobalUnLock

1. 首先我們來看HeapAlloc:MSDN上的解釋為:HeapALloc是從堆上分配一塊內存,且分配的內存是不可移動的(即假設沒有連續的空間能滿足分配的大小,程序不能將其它零散的空間利用起來,從而導致分配失敗)。該分配方法是從一指定地址開始分配,而不像GloabalAlloc是從全局堆上分配,這個有可能是全局,也有可能是局部。函數原型為:LPVOID HeapAlloc(HANDLEhHeap,DWORDdwFlags,SIZE_TdwBytes);hHeap是進程堆內存開始位置。

dwFlags是分配堆內存的標誌。

包含HEAP_ZERO_MEMORY,即使分配的空間清零。

dwBytes是分配堆內存的大小。

  其相應的釋放空間函數為HeapFree.

2. 再看GlobalAlloc:該函數用於從全局堆中分配出內存供程序使用,函數原型為:HGLOBALGlobalAlloc(UINTuFlags,SIZE_TdwBytes);uFlags參數含義GHND GMEM_MOVEABLE和GMEM_ZEROINIT的組合GMEM_FIXED 分配固定內存,返回值是一個指針GMEM_MOVEABLE 分配活動內存,在Win32中。內存塊不能在物理內存中移動,但能在默認的堆中移動。返回值是內存對象的句柄。用函數GlobalLock可將句柄轉化為指針GMEM_ZEROINIT 將內存內容初始化為零GPTR GMEM_FIXED和GMEM_ZEROINIT的組合普通情況下我們在編程的時候,給應用程序分配的內存都是能夠移動的或者是能夠丟棄的,這樣能使有限的內存資源充分利用,所以,在某一個時候我們分配的那塊內存的地址是不確定的,由於他是能夠移動的。所以得先鎖定那塊內存塊。這兒應用程序須要調用API函數GlobalLock函數來鎖定句柄。例如以下:lpMem=GlobalLock(hMem);這樣應用程序才幹存取這塊內存。所以我們在使用GlobalAllock時。通常搭配使用GlobalLock。當然在不使用內存時,一定記得使用GlobalUnlock,否則被鎖定的內存塊一直不能被其它變量使用。

GlobalAlloc相應的釋放空間的函數為GlobalFree.

3.LocalAlloc:該函數用於從局部堆中分配內存供程序使用,函數原型為:HLOCALLocalAlloc(UINTuFlags。SIZE_TuBytes);參數同GlobalAlloc.在16位Windows中是有差別的,由於在16位windows用一個全局堆和局部堆來管理內存,每個應用程序或dll裝入內存時。代碼段被裝入全局堆。而系統又為每個實例從全局堆中分配了一個64kb的數據段作為該實例的局部堆,用來存放應用程序的堆棧和全部全局或靜態變量。

而LocalAlloc/GlobalAlloc就是分別用於在局部堆或全局堆中分配內存。

  因為每一個進程的局部堆非常小,所以在局部堆中分配內存會受到空間的限制。但這個堆是每一個進程私有的,相對而言分配數據較安全,數據訪問出錯不至於影響到整個系統。

  而在全局堆中分配的內存是為各個進程共享的,每一個進程僅僅要擁有這個內存塊的句柄都能夠訪問這塊內存。可是每一個全局內存空間須要額外的內存開銷。造成分配浪費。並且一旦發生嚴重錯誤,可能會影響到整個系統的穩定。

  只是在Win32中。每一個進程都僅僅擁有一個省缺的私有堆。它僅僅能被當前進程訪問。應用程序也不可能直接訪問系統內存。

所以在Win32中全局堆和局部堆都指向進程的省缺堆。用LocalAlloc/GlobalAlloc分配內存沒有不論什麽差別。甚至LocalAlloc分配的內存能夠被GlobalFree釋放掉。所以在Win32下編程,無需註意Local和Global的差別,一般的內存分配都等效於HeapAlloc(GetProcessHeap(),……)。

LocalAlloc相應的釋放函數為LockFree.

4.VirtualAlloc:該函數的功能是在調用進程的虛地址空間,預定或者提交一部分頁。假設用於內存分配的話,而且分配類型未指定MEM_RESET。則系統將自己主動設置為0;其函數原型:LPVOIDVirtualAlloc(LPVOIDlpAddress。// region to reserve or commit SIZE_T dwSize, // size of region DWORDflAllocationType,// type of allocation DWORD flProtect // type of access protection);VirtualAlloc能夠通過並行多次調用提交一個區域的部分或所有來保留一個大的內存區域。多重調用提交同一塊區域不會引起失敗。這使得一個應用程序保留內存後能夠任意提交將被寫的頁。

當這樣的方式不在有效的時候,它會釋放應用程序通過檢測被保留頁的狀態看它是否在提交調用之前已經被提交。

VirtualAlloc相應的釋放函數為VirtualFree.

[new,malloc,GlobalAlloc具體解釋]


new,malloc,GlobalAlloc具體解釋