Windows進程堆

前言

進程堆是進程非常重要的內存區域,它裏面含有了進程中分配的變量信息等,一個進程被創建時會自動創建一個默認堆,進程默認堆非常重要,系統要求進程中的線程依次訪問默認堆,意味如果一個線程要對默認堆分配內存,那麼其他線程一定要處於等待狀態。一個進程在運行時 會創建多個堆,這些堆可以創建,也可以銷燬。調用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
);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章