Windows驱动内存操作

内存复制

内存复制分两种情况,非重叠和可重叠

如图:当复制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使用场景

  1. 每次申请固定大小的内存
  2. 申请和回收内存操作频繁

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);
}

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章