前言
進程堆是進程非常重要的內存區域,它裏面含有了進程中分配的變量信息等,一個進程被創建時會自動創建一個默認堆,進程默認堆非常重要,系統要求進程中的線程依次訪問默認堆,意味如果一個線程要對默認堆分配內存,那麼其他線程一定要處於等待狀態。一個進程在運行時 會創建多個堆,這些堆可以創建,也可以銷燬。調用GetProcessHeap可以獲取默認堆
HANDLE GetProcessHeap();
堆的創建
進程運行時產生的數據不能都放在默認堆中,因此需要創建額外的堆來存放信息,創建堆的函數如下:
HANDLE HeapCreate(
DWORD flOptions ,
DWORD dwInitialSize ,
DWORD dwMaxmumSize);
第一個參數flOptions 表明對堆的操作,取證範圍是:0、HEAP_NO_SERIALIAZE、HEAP_CREATE_ENABLE_EXECUTE、HEAP_GENERATE_EXCEPTIONS
取值 | 含義 |
---|---|
HEAP_NO_SERIALIAZE | 表明線程對堆的操作是非互斥的,不需要依次訪問創建的堆、但是這個標誌不能應用在低碎片化堆中 |
HEAP_CREATE_ENABLE_EXECUTE | 從該堆分配的所有內存塊均允許執行代碼 |
HEAP_GENERATE_EXCEPTIONS | 系統引發異常以指示對HeapAlloc和HeapReAlloc的調用失敗(例如,內存不足的情況),而不是返回NULL。 |
第二個參數是設置分配堆的內存初始化大小
第三個參數是設置堆的最大大小,如果值爲0的話表明堆的內存大小沒有限制,可以不斷增長。
塊的創建
創建了堆之後,就需要創建內存塊來存放信息,系統提供了創建內存塊的函數,下面是創建塊的函數
DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
HANDLE hHeap,
DWORD dwFlags,
SIZE_T dwBytes
);
第一個參數hHeap表明,在哪個堆中分配內存塊;
第二個參數表明堆分配選項,指定這些值中的任何一個都將覆蓋使用HeapCreate創建堆時指定的相應值。 此參數可以是以下一個或多個值。
取值 | 含義 |
---|---|
HEAP_GENERATE_EXCEPTIONS | 系統將引發異常以指示功能故障(例如內存不足情況),而不是返回NULL。 |
HEAP_NO_SERIALIZE | 線程不依次訪問內存塊 |
HEAP_ZERO_MEMORY | 分配的內存將初始化爲零, 否則,內存不會初始化爲零。 |
第三個參數表明分配的字節數
調整塊的大小
塊創建之後,大小可以重調,爲了不浪費內存可以調小,爲了能夠使用到足夠的內存,可以調大,重調函數如下:
DECLSPEC_ALLOCATOR LPVOID HeapReAlloc(
HANDLE hHeap,
DWORD dwFlags,
_Frees_ptr_opt_ LPVOID lpMem,
SIZE_T dwBytes
);
第一個參數hHeap表明,在哪個堆中的內存塊需要重調;
第二次參數是堆重新分配選項。 使用HeapCreate函數創建堆時,指定值將覆蓋flOptions參數中指定的相應值。取值情況如下:
取值 | 含義 |
---|---|
HEAP_GENERATE_EXCEPTIONS | 操作系統引發異常以指示功能故障(例如內存不足情況),而不是返回NULL。 |
HEAP_NO_SERIALIZE | 同上 |
HEAP_REALLOC_IN_PLACE_ONLY | 重新分配內存塊時不能移動。 如果未指定該值,則該功能可能會將塊移動到新位置。 如果指定了該值並且無法移動就無法調整該塊的大小,則該功能將失敗,從而使原始存儲塊保持不變。 |
HEAP_ZERO_MEMORY | 如果重新分配請求用於更大的大小,則超出原始大小的其他內存區域將初始化爲零。 直到其原始大小的存儲塊的內容均不受影響。 |
第三個參數是指向該函數重新分配的內存塊的指針。 該指針是通過較早調用HeapAlloc或HeapReAlloc函數返回的。
第四個參數是重新分配塊的大小
銷燬堆
堆既然能被創建就能被銷燬,當程序不再需要自己的堆時,程序可以自動銷燬它,但程序不主動銷燬它的話,系統只能等進程被終止了,系統才自動銷燬它,銷燬堆的函數如下:
BOOL HeapDestroy(
HANDLE hHeap
);
成功銷燬則返回true,否則返回false
堆的使用
我們平時編程的時候,很少直接去調用堆相關的api去創建和操作堆,但我們卻經常用到堆,比如在c++中的new 操作,new操作就是在堆中分配內存,爲了形象顯示new創建的堆的過程,我借鑑瞭如下代碼:
class CSomeClass{
public:
static HANDLE s_handle;
static UINT s_allocInheap;
public:
void* operator new(size_t hsize);
void operator delete(void* p);
};
void* CSomeClass::operator new(size_t hsize)
{
if(s_handle==NULL)
{
s_handle=HeapCreate(HEAP_NO_SERIALIZE,0,0);
if(s_handle==NULL)
return NULL;
}
void* p=HeapAlloc(s_handle,0,hsize);
if(p!=NULL)
s_allocInheap++;
else
return NULL;
return (p);
}
上面的代碼,覆蓋了系統的new操作,當調用一次new操作時,程序就會分配一個內存塊並讓塊數加1.
遍歷所有堆
Windows api裏有GetProcessHeaps這個函數,該函數可以獲取進程創建的所有堆,遍歷所有堆之前需要自定義一個句柄數組。GetProcessHeaps函數如下:
HANDLE GetProcessHeaps(
DWORD dWNumHeaps,
PHANDLE phHeaps
);