1. Lookaside結構
頻繁的申請和回收記憶體,會導致在記憶體上產生大量的記憶體“空洞”,從而導致最終無法申請記憶體。DDK為程式員提供了Lookaside結構來解決這個問題。
我們可以將Lookaside對象看成是一個記憶體容器。在初始化的時候,它先向Windows申請了一塊比較大的記憶體。以後程式員每次申請記憶體的時候,不是直接向Windows申請記憶體,而是想Lookaside對象申請記憶體。Looaside會智能的避免產生記憶體“空洞”。如果Lookaside對象內部記憶體不夠用時,它會向作業系統申請更多的記憶體。
Lookaside一般會在以下情況下使用:
1. 程式員每次申請固定大小的記憶體。
2. 申請和回收的操作十分頻繁。
要使用Looaside對象,首先要初始化Lookaside對象,有以下兩個函數可以使用:
(1)VOID
ExInitializeNPagedLookasideList(
IN PNPAGED_LOOKASIDE_LIST Lookaside,
IN PALLOCATE_FUNCTION Allocate OPTIONAL,
IN PFREE_FUNCTION Free OPTIONAL,
IN ULONG Flags,
IN SIZE_T Size,
IN ULONG Tag,
IN USHORT Depth
);
(2)VOID
ExInitializePagedLookasideList(
IN PPAGED_LOOKASIDE_LIST Lookaside,
IN PALLOCATE_FUNCTION Allocate OPTIONAL,
IN PFREE_FUNCTION Free OPTIONAL,
IN ULONG Flags,
IN SIZE_T Size,
IN ULONG Tag,
IN USHORT Depth
);
初始化玩Lookaside對象後,可以進行申請記憶體的操作了:
(1)PVOID
ExAllocateFromNPagedLookasideList(
IN PNPAGED_LOOKASIDE_LIST Lookaside
);
(2)PVOID
ExAllocateFromPagedLookasideList(
IN PPAGED_LOOKASIDE_LIST Lookaside
);
對Lookaside對象回收記憶體:
(1)VOID
ExFreeToNPagedLookasideList(
IN PNPAGED_LOOKASIDE_LIST Lookaside,
IN PVOID Entry
);
(2)VOID
ExFreeToPagedLookasideList(
IN PPAGED_LOOKASIDE_LIST Lookaside,
IN PVOID Entry
);
在使用完Lookaside對象後,要刪除Lookaside對象:
(1)VOID
ExDeleteNPagedLookasideList(
IN PNPAGED_LOOKASIDE_LIST Lookaside
);
(2) VOID
ExDeletePagedLookasideList(
IN PPAGED_LOOKASIDE_LIST Lookaside
);
測試代碼:
#pragma INITCODEVOID LookasideTets(){ KdPrint(("進入LookasideTest函數!\n")); PAGED_LOOKASIDE_LIST Lookaside; ExInitializePagedLookasideList(&Lookaside, NULL, NULL, 0, sizeof(MYDATASTRUCT), 'abcd', 0); PMYDATASTRUCT pMyData[50]; for (int i=0; i<50; i++) { pMyData[i] = (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&Lookaside); if ((i+1)%10 == 0) { KdPrint(("申請了 %d 個資料了!\n", ++i)); } } for (int i=0; i<50; i++) { ExFreeToPagedLookasideList(&Lookaside, pMyData[i]); pMyData[i] = NULL; if ((i+1)%10 == 0) { KdPrint(("釋放了 %d 個資料的記憶體了!\n", ++i)); } } ExDeletePagedLookasideList(&Lookaside);}
2.運行時函數
(1)記憶體間複製(非重疊)
VOID
RtlCopyMemory(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
(2)記憶體間複製(可重疊)
VOID
RtlMoveMemory(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
(3)填充記憶體
VOID
RtlFillMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length,
IN UCHAR Fill
);
VOID
RtlZeroMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length
);
(4)記憶體比較
SIZE_T
RtlCompareMemory(
IN CONST VOID *Source1,
IN CONST VOID *Source2,
IN SIZE_T Length
);
ULONG
RtlEqualMemory(
CONST VOID *Source1,
CONST VOID *Source2,
SIZE_T Length
);
#define BUFFER_SIZE 1024#pragma INITCODEVOID RtlTest(){ KdPrint(("進入RtlTest函數!\n")); PUCHAR pBuffer1 = (PUCHAR)ExAllocatePool(PagedPool, BUFFER_SIZE); RtlZeroMemory(pBuffer1, BUFFER_SIZE); PUCHAR pBuffer2 = (PUCHAR)ExAllocatePool(PagedPool, BUFFER_SIZE); RtlFillMemory(pBuffer2, BUFFER_SIZE, 0xAA); RtlCopyMemory(pBuffer1, pBuffer2, BUFFER_SIZE); if (RtlEqualMemory(pBuffer1, pBuffer2, BUFFER_SIZE)) { KdPrint(("兩塊記憶體塊資料一樣!\n")); for(int i=0; i<BUFFER_SIZE; i++) { KdPrint(("%02X", pBuffer1[i])); } } else { KdPrint(("兩塊記憶體塊資料不一樣!\n")); } KdPrint(("離開RtlTest函數!\n"));}