内存复制
内存复制分两种情况,非重叠和可重叠
如图:当复制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);
}