1. 程式人生 > >記憶體分配函式 ExAllocatePool ExAllocatePoolWithTag

記憶體分配函式 ExAllocatePool ExAllocatePoolWithTag

如同C裡面的malloc一樣,核心模式下的ExAllocatePool也是非常重要的.但是一說到ExAllocatePool函式就不得不提ExAllocatePoolWithTag函式.對比一下兩個函式的呼叫方式:

     PVOID p = ExAllocatePool(Pool_Type, Size);

    PVOID p = ExAllocatePoolWithTag(Pool_Type, Size, Tag);

    在呼叫ExAllocatePoolWithTag的時候,系統會在要求的記憶體大小的基礎上再額外多分配4個位元組的標籤.這個標籤佔用了開始的4個位元組,位於返回指標所指向地址的前面.這樣,當除錯時這個標籤可以幫助你識別有問題的記憶體塊.

   在WDM.H(NTDDK.H)中聲明瞭,記憶體分配函式無條件受預處理巨集POOL_TAGGING控制(POOL_TAGGING被無條件的定義).因此,即便是呼叫的ExAllocatePool函式,實際執行的卻是:ExAllocatePoolWithTag,其加入的標籤為"mdW",指明是WDM的記憶體塊.

   又或者你強行關閉POOL_TAGGING巨集再去呼叫ExAllocatePool,實際執行的還是ExAllocatePoolWithTag,並帶標籤"enoN".

   因此,建議在分配記憶體時,直接呼叫ExAllocatePoolWithTag並加上一個自定義的標籤.

====================================================================

ExAllocatePoolWithTag

功能描述

ExAllocatePoolWithTag函式:根據指定儲存區型別引數分配一段空間,並把該空間的首地址作為返回值傳送給呼叫者。


引數說明:

PoolType
該引數用來指定想要申請的記憶體的型別(核心空間中的記憶體主要分成兩類;分頁記憶體區,和未分頁記憶體區)。查詢可選的記憶體區型別可以到MSDN查詢POOL_TYPE結構。

您也可以修改該引數,將當前的值和標誌POOL_RAISE_IF_ALLOCATION_FAILURE進行或運算(使用運算子:||)。標誌POOL_RAISE_IF_ALLOCATION_FAILURE的作用是在申請空間的請求無法被實現的時候(空間不足?許可權不足?)報出異常。但是我們不建議您過多使用這個標誌位,因為它對程式的效能影響太大~

同樣,您也可以把當前的PoolType和另一個標誌POOL_COLD_ALLOCATION進行或運算(使用運算子:||)。這個標誌的功能是提示系統從那些快要頁面溢位(Paged-out)的頁中分配空間(反正這個頁面中資料基本壞了,直接分配給其他人用,是這意思嗎?)。為了儘可能的減少常駐儲存器池的數量,您還是少用這個標誌。同時POOL_COLD_ALLOCATION 標誌位只建議您在XP和之後的windows版本中使用(看來其中有不可告人的祕密)。

NumberOfBytes
通過該引數指定想要分配的記憶體的位元組數。

Tag
為將要被分配的空間指定標誌(就是給你得到的空間取個獨一無二的名字)。進一步解釋:賦給該引數的內容是一個字串常量,最多可以包含四個字母,該字串應該放到單引號當中(比如:‘tag1’‘tag2’)。另外,這個字串常常是逆序的,如,‘1gaT’(所以大家會發現輸入這個引數的串確實都是倒過來的。。。)。輸入到這個引數中的每一個字元的ASCII值都必須在0-127之間。每次的申請空間的時候都最好應該使用一個獨一無二的標識,這樣可以幫助偵錯程式和檢查器辨認和分析。

返回值:
如果該函式發現目前系統的自由空間不足,就會返回NULL。否則,將返回指向被分配出來的空間的首地址。

附加說明:
這個函式用於普通的申請記憶體空間。
如果引數NumberOfBytes 的值大於等於PAGE_SIZE ,那麼函式就會按照頁對齊(以頁為單位)分配空間。當分配小於等於一個頁大小的空間時,函式會在一個單獨的頁中進行分配,也就是說該情況下分配的空間不會誇頁。同時,分配少於一個頁大小的空間時,分配是以位元組為對齊單位,在32位系統中以8位元組對齊,在64位系統中以16位元組對齊。
要成功的用該函式申請空間,需要在申請非分頁記憶體區的時候,引數NumberOfBytes 小於PAGE_SIZE,並且要給出想要申請的準確位元組數。如果成功的申請到了大於一個頁的空間,並且引數NumberOfBytes不是頁大小的倍數,那麼最後一頁會含有不屬於該函式呼叫者的空間。如果可能的話,記憶體分配管理器會佔用這些空間。為了防止發生資料訪問衝突,驅動程式只能操作已經顯式申請過的儲存空間。

系統將空間標識(第三個引數)和空間繫結起來。偵錯程式,如WinDbg,可以顯式這些和記憶體空間繫結在一起的識別符號。Gflag(一個windows自帶的除錯工具),可以開啟一個系統功能——請求為一個特定的標示符申請專有的空間。Poolmon,該工具包含在WDK中,可以通過給定的標示符追蹤記憶體區域。

Tag引數的值有時候會被以逆序的方式儲存或者顯示。如一個呼叫函式傳進來引數‘Fred’。而這個引數在其他地方或者被其他偵錯程式顯示出來時則是‘derF’。而在暫存器和某些工具中顯示為‘0x64657246’

該函式申請到的空間在釋放的時候可以使用ExFreePool或者ExFreePoolWithTag。

函式ExAllocatePoolWithTag的呼叫者的核心中斷級必須小於等於DISPATCH_LEVEL。如果呼叫者在DISPATCH_LEVEL級上執行,必須使用NonPagedXxx給PoolType複製,如果呼叫者的工作中斷級小於等於APC_LEVEL,那麼它在型別引數上也可以使用POOL_TYPE。但是中斷級和其他環境引數必須充分考慮分頁型別的空間。

注意:不要把NumberOfBytes設定成0,這會造成空間浪費,因為系統會給每一次分配的空間加一個頭,哪怕分配的空間大小是0,同時還會在函式的呼叫者程式碼中產生一些潛在的問題。
注意:被ExAllocatePoolWithTag分配出來的空間是沒有經過初始化的。一個核心驅動如果打算申請一段空間,並且讓應用層的程式可以訪問這個空間,必須先對它進行清零的初始化。