內存複製
內存複製分兩種情況,非重疊和可重疊
如圖:當複製A~C到B~D段內存b-c段內存重疊
RtlCopyMemory爲非重疊複製,即不能使用RtlCopyMemory操作上圖中的內存段,RtlMoveMemory爲可重疊複製,此函數對內存是否重疊進行判斷。
void RtlCopyMemory(
Destination, //表示要複製內存的目的地址
Source, //表示要複製內存的源地址
Length //表示複製內存長度,單位是字節
);
void RtlMoveMemory(
Destination, //表示要複製內存目的地址
Source, //表示要複製內存的源地址
Length //表示要複製內存的長度,單位是字節
);
與RtlCopyMemory相似函數RtlcopyBytes,這個函數參數一樣,功能完全一樣。RtlCopyMemory函數的內部實現方法是依靠memcpy函數實現的,C99定義,memcpy沒有考慮重疊部分,因此它不能保障重疊部分是否被複制。
RtlMoveMemory內部實現爲memmove,爲了保證重疊部分正確複製,C99規定memmove函數完成,這個函數對兩個內存是否重疊進行了判斷,但影響到速度,如果能確保複製的內存沒有重疊,使用memcpy函數。爲了保證可移植性,DDK用宏對memmove進行了封裝,即RtlMoveMemory。
內存填充
固定字節填充:RtlFillMemory
//依靠memset實現
#define RtlFillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length))
//函數定義
void RtlFillMemory(
Destination, //目的地址
Length, //長度
Fill // 需要填充的字節
);
內存填零:RtlZeroMemory
#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
//定義
void RtlZeroMemory(
Destination, //目的地址
Length //長度
);
內存比較
RtlCompareMemory比較兩塊內存是否一致。
RtlCompareMemory(
_In_ const VOID* Source1, //比較第一個內存地址
_In_ const VOID* Source2, //比較第二個內存地址
_In_ SIZE_T Length //比較長度,單位爲字節
);
//返回值:相等的字節數
如果RtlCompareMemory返回值與指定的Length相等兩個內存完全一致
同時,RtlEqualMemory直接判斷兩段內存是否一致,當兩段內存一致返回非零值,不一致返回零值。
#define RtlEqualMemory(Destination,Source,Length) (!memcmp((Destination),(Source),(Length)))
內存操作示例:
VOID RtlTestMemory() {
PUCHAR pBuffer = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
//用零填充內存
RtlZeroMemory(pBuffer,BUFFER_SIZE);
PUCHAR pBuffer2 = (PUCHAR)ExAllocatePool(PagedPool,BUFFER_SIZE);
//用固定字節填充內存 (用AA填充)
RtlFillMemory(pBuffer2,BUFFER_SIZE,0xAA);
//內存複製
RtlCopyMemory(pBuffer,pBuffer2,BUFFER_SIZE);
//判斷內存是否一致
ULONG uRet = RtlCompareMemory(pBuffer,pBuffer2,BUFFER_SIZE);
if (uRet == BUFFER_SIZE) {
KdPrint(("The two blocks are same.\n"));
}
//宏判斷內存是否一致
ULONG uRet=RtlEqualMemory(pBuffer,pBuffer2,BUFFER_SIZE);
if (uRet != 0) {
KdPrint(("The two blocks are same.\n"));
}
}
使用Lookaside提高申請內存效率
頻繁向系統申請內存會導致內存空洞,即使用內存中有大量可用內存,也會導致申請失敗,在系統空閒時候,系統會整理內存中
空洞,將內存中空洞進行合併。
內存空洞實際是連續申請內存時,內存是連續的,期間有內存回收後再次申請比回收的大是就無法申請成功,導致內存空洞。如圖:
在操作系統空閒時,系統會整理內存空洞,將內存中的空洞進行合併。
使用Lookaside時,它會事先向windows申請一塊比較大的內存,程序員申請內存時是向Lookaside對象申請內存。Lookaside會避免內存空洞。當Lookaside內存不夠用會繼續向windows申請更多內存。當有大量未使用的內存時,會自動讓windows回收。Lookaisde類似於自動的內存分配容器。使用Lookaside效率高於直接向windows申請內存。
Lookaside使用場景
- 每次申請固定大小的內存
- 申請和回收內存操作頻繁
Lookaside對象使用工程:初始化-->申請內存-->內存回收-->刪除Lookaside對象。
Lookaside對象非分頁與分頁初始化:
//非分頁初始化
VOID ExInitializeNPagedLookasideList (
_Out_ PNPAGED_LOOKASIDE_LIST Lookaside,
_In_opt_ PALLOCATE_FUNCTION Allocate,
_In_opt_ PFREE_FUNCTION Free,
_In_ ULONG Flags,
_In_ SIZE_T Size,
_In_ ULONG Tag,
_In_ USHORT Depth
);
//分頁初始化
VOID ExInitializePagedLookasideList (
_Out_ PPAGED_LOOKASIDE_LIST Lookaside,
_In_opt_ PALLOCATE_FUNCTION Allocate,
_In_opt_ PFREE_FUNCTION Free,
_In_ ULONG Flags,
_In_ SIZE_T Size,
_In_ ULONG Tag,
_In_ USHORT Depth
);
Lookaside對象非分頁與分頁申請內存:
//非分頁申請
PVOID ExAllocateFromNPagedLookasideList (
_Inout_ PNPAGED_LOOKASIDE_LIST Lookaside
)
//分頁申請
PVOID ExAllocateFromPagedLookasideList (
_Inout_ PPAGED_LOOKASIDE_LIST Lookaside
)
Lookaside對象非分頁與分頁內存回收:
//非分頁內存回收
VOID ExFreeToNPagedLookasideList (
_Inout_ PNPAGED_LOOKASIDE_LIST Lookaside,
_In_ __drv_freesMem(Mem) PVOID Entry
)
//分頁內存回收
VOID ExFreeToPagedLookasideList (
_Inout_ PPAGED_LOOKASIDE_LIST Lookaside,
_In_ __drv_freesMem(Mem) PVOID Entry
)
刪除Lookaside對象:
//非分頁刪除Lookaside對象
VOID ExDeleteNPagedLookasideList (
_Inout_ PNPAGED_LOOKASIDE_LIST Lookaside
);
//分頁刪除Lookaside對象
VOID ExDeletePagedLookasideList (
_Inout_ PPAGED_LOOKASIDE_LIST Lookaside
);
Lookaside對象使用實例:
#define ARRAY_NUMBER 50
typedef struct _MYDATASTRUCT {
LIST_ENTRY ListEntry;
ULONG x;
ULONG y;
}MYDATASTRUCT,*PMYDATASTRUCT;
//LookasideTest函數實現Lookaside操作
VOID LookasideTest() {
//初始化Lookaside對象
PAGED_LOOKASIDE_LIST pageList;
ExInitializePagedLookasideList(&pageList,NULL,NULL,0,sizeof(MYDATASTRUCT),'1234',0);
PMYDATASTRUCT MyObjectarry[ARRAY_NUMBER];
//頻繁申請內存
for (int i = 0; i < ARRAY_NUMBER; i++) {
MyObjectarry[i] = (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&pageList);
}
//頻繁回收內存
for (int i = 0; i386 < ARRAY_NUMBER; i++)
{
ExFreeToPagedLookasideList(&pageList,MyObjectarry[i]);
MyObjectarry[i] = NULL;
}
//刪除Lookaside對象
ExDeletePagedLookasideList(&pageList);
}