《Windows核心程式設計》學習筆記(14) 堆

2021-09-06 04:16:13 字數 4280 閱讀 9365

堆非常適合分配大量的小型資料。它是用來管理鍊錶和樹的最佳方式。但是它分配和釋放記憶體塊的速度比虛擬記憶體和記憶體對映檔案要慢,而且也無法再對物理儲存器的調撥和撤銷調撥進行直接控制。

乙個程序同時可以有多個堆,程序在整個生命週期內可以建立和銷毀這些堆。但是, 預設的堆是在程序開始執行之前由系統自動建立的,在程序終止後會自動銷毀。我們無法銷毀程序的預設堆。每個堆都有乙個用來標識自己的堆控制代碼,所有分配和釋 放記憶體塊的堆函式都會在引數中用到這個堆控制代碼。

我們可以呼叫如下函式來得到程序預設堆得控制代碼:

handle winapi getprocessheap(void);

建立額外的堆

handle winapi heapcreate(
__in          dword floptions

,

__in          size_t dwinitialsize

,

__in          size_t dwmaximumsize

);
floptions

引數用來表示對堆的操作該如何進行。可以指定0

heap_no_serialize

heap_generate_exceptions

heap_create_enable_execute

heap_no_serialize標誌使得多個執行緒可以同時訪問乙個堆,這使得堆中的資料可能會遭到破壞,因此應該避免使用。

heap_generate_exceptions標誌告訴系統,每當在堆中分配或者重新分配記憶體塊失敗的時候,丟擲乙個異常。

heap_create_enable_execute標誌告訴系統,我們想在堆中存放可執行**。如果不設定這個標誌,那麼當我們試圖在來自堆的記憶體塊中執行**時,系統會丟擲

exception_access_violation

異常。

dwinitialsize

引數表示一開始要調撥給堆的位元組數。如果需要,

heapcreate

會把這個值向上取整到

cpu頁面大小的整數倍。

dwmaximumsize

引數表示堆能增長到的最大大小。如果

dwmaximumsize 大於

0,那麼建立的堆會有乙個最大大小。

如果dwmaximumsize為0

,那麼建立的堆將是可增長的,直到用盡所有的物理儲存器為止。

從堆中分配記憶體塊

lpvoid winapi heapalloc(
__in          handle hheap

,

__in          dword dwflags

,

__in          size_t dwbytes

);

調整記憶體塊的大小

lpvoid winapi heaprealloc(
__in          handle hheap

,

__in          dword dwflags

,

__in          lpvoid lpmem

,

__in          size_t dwbytes

);
dwflags

引數可以是heap_generate_exceptions

heap_no_serialize

heap_zero_memory

heap_realloc_in_place_only

heap_zero_memory這個標誌只有在增大記憶體塊的大小時才有用。在這種情況下,記憶體中的額外位元組會被清零。減小記憶體塊的大小時,這個標誌不起任何作用。

heap_realloc_in_place_only在增大記憶體塊的時候,

heaprealloc

可能會在堆內部移動記憶體塊,而這個標誌用來告訴

heaprealloc

不要移動記憶體塊。

如果heaprealloc

函式能在不移動記憶體塊的前提下就能讓它增大,那麼函式會返回原來的記憶體塊位址。另一方面,如果

heaprealloc

必須移動記憶體塊的位址,那麼函式將返回乙個指向一塊更大記憶體塊的新位址。

如果乙個記憶體塊是鍊錶或者樹的一部分,那麼需要指定這個標誌。因為鍊錶或者樹的其他節點可能包含指向當前節點的指標,把節點移動到堆中其他的地方會破壞鍊錶或樹的完整性。

lpmem

和dwbytes

引數分別用來指定想要調整大小的記憶體塊的原始位址以及記憶體塊的新大小,以位元組為單位。

獲得記憶體塊的大小

分配一塊記憶體後,可以呼叫如下函式來得到這塊記憶體的實際大小:

size_t winapi heapsize(
__in          handle hheap

,

__in          dword dwflags

,

__in          lpcvoid lpmem

);
引數

hheap

用來標識堆。

引數dwflags

可以是0

或者heap_no_serialize。

引數lpmem

標識記憶體塊快的位址。

釋放記憶體塊

bool winapi heapfree(
__in          handle hheap

,

__in          dword dwflags

,

__in          lpvoid lpmem

);

銷毀堆

bool winapi heapdestroy(
__in          handle hheap

);
呼叫這個函式的時候,系統會釋放堆中包含的所有記憶體塊,同時系統會收回堆所占用的物理儲存器和位址空間區域。

其他堆函式

1.toolhelp

函式允許我們列舉程序中的堆以及堆中分配的記憶體塊。

heap32first

,heap32next

,heap32listfirst

,heap32listnext。

2.得到程序中所有堆的控制代碼

dword winapi getprocessheaps(
__in          dword numberofheaps

,

__out         phandle processheaps

);
用法如下:

handle hheaps[25];

dword dwheaps = getprocessheaps(25, hheaps);

if(dwheaps > 25)

else

注意:函式所返回的控制代碼陣列中也包括了程序的預設堆控制代碼。

3.驗證堆的完整性

bool winapi heapvalidate(
__in          handle hheap

,

__in          dword dwflags

,

__in          lpcvoid lpmem

);
通常呼叫這個函式的時候,

我們會傳入乙個堆控制代碼,和乙個標誌

0,並傳

null

給lpmem。

該函式會遍歷堆中的各個記憶體塊,確保沒有任何一塊記憶體被破壞。

4.為了讓堆中閒置的記憶體塊能重新接合在一起,並撤銷調撥給堆中閒置記憶體塊的儲存器,可以呼叫如下函式:

size_t winapi heapcompact(
__in          handle hheap

,

__in          dword dwflags

);
一般來說,我們會傳0 給

dwflags

引數。

windows核心程式設計筆記(一)

1.setwindowredraw 設定視窗的可重繪狀態 這個函式是不是把整個視窗 包括視窗控制項 的和重繪相關的訊號 遮蔽掉了?2.combobox setitemdata 巨集 函式原型 int combobox setitemdata hwnd hwndctl,空間控制代碼 int index...

《Windows核心程式設計》筆記1 核心物件

由於.net framework中很多地方需要用到以前win32中的一些知識點,不了解其中的來朧去脈學習起來會比較吃力,於是準備用點時間補一下windows 核心方面的知識點,參考書本是經典的核心物件是核心分配的乙個記憶體塊,這種記憶體塊是乙個資料結構,表示核心物件的各種特徵。並且只能由核心來訪問。...

Windows核心程式設計筆記 (3)核心物件

每個核心物件都只是乙個記憶體塊,它由作業系統核心分配,並只能由作業系統核心訪問,這個記憶體塊是乙個資料結構,其成員維護著於物件相關的資訊。少數成員是所有物件都有的,像安全描述符和使用計數等 大多數成員是特有的,像程序物件的程序id,檔案物件的位元組偏移量。由於核心物件的資料結構只能由作業系統核心訪問...