windows内核驱动内存管理之Lookaside使用
Windows内存管理中使用了类似于容器的东西,叫做Lookaside对象,每次程序员申请内存都会从Lookaside里面申请,只有不足的时候,Lookaside才会向内存又一次申请内存空间,这样减少了频繁申请内存而导致的内存碎片。
当Lookaside对象内部有大量没有使用的内存时候,它会自动让windows回收一部分内存,总之,Lookaside很智能。
一般Lookaside用于以下情况:
(1)程序员每次申请固定的内存大小
(2)申请和回收内存的次数较多,很频繁
开发环境:
VS2012+WDK7.1
初始化Lookaside对象:
分页:
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 );
非分页:
VOID ExInitializeNPagedLookasideList( _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 );
回收内存
VOID ExFreeToPagedLookasideList( _Inout_ PPAGED_LOOKASIDE_LIST Lookaside, _In_ PVOID Entry );
/************************************************************************ * 文件名称:main.cpp * 作 者:Geons * 完成日期:2016年3月27日11:03:20 *************************************************************************/ #include "driver.h" typedef struct _MYDATASTRUCT { CHAR buffer[64]; }MYDATASTRUCT, *PMYDATASTRUCT; #pragma INITCODE VOID LookasideTest() { // 初始化 PAGED_LOOKASIDE_LIST pageList; ExInitializePagedLookasideList(&pageList, NULL, NULL, 0, sizeof(MYDATASTRUCT), '1234', 0); #define ARRAY_NUMBER 50 PMYDATASTRUCT MyObjectArray[ARRAY_NUMBER]; // 模拟频繁申请内存 for(int i = 0; i< ARRAY_NUMBER; i++) { MyObjectArray[i] = (PMYDATASTRUCT)ExAllocateFromPagedLookasideList(&pageList); KdPrint(("正在申请第%d个内存\n", i+1)); } // 模拟频繁回收内存 for(int i = 0; i<ARRAY_NUMBER;i++) { ExFreeToPagedLookasideList(&pageList, MyObjectArray[i]); MyObjectArray[i] = NULL; KdPrint(("正在回收第%d个空间\n", i+1)); } // 删除LokkList ExDeletePagedLookasideList(&pageList); } /************************************************************************ * 函数名称:DriverEntry * 功能描述:初始化驱动程序,定位和申请硬件资源,创建内核对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 pRegistryPath:驱动程序在注册表的中的路径 * 返回 值:返回初始化驱动状态 *************************************************************************/ #pragma INITCODE extern "C" NTSTATUS DriverEntry ( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath ) { NTSTATUS status; KdPrint(("Enter DriverEntry\n")); //注册其他驱动调用函数入口 pDriverObject->DriverUnload = HelloDDKUnload; pDriverObject->MajorFunction[IRP_MJ_CREATE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_WRITE] = HelloDDKDispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_READ] = HelloDDKDispatchRoutine; //创建驱动设备对象 status = CreateDevice(pDriverObject); LookasideTest(); KdPrint(("DriverEntry end\n")); return status; } /************************************************************************ * 函数名称:CreateDevice * 功能描述:初始化设备对象 * 参数列表: pDriverObject:从I/O管理器中传进来的驱动对象 * 返回 值:返回初始化状态 *************************************************************************/ #pragma INITCODE NTSTATUS CreateDevice ( IN PDRIVER_OBJECT pDriverObject) { NTSTATUS status; PDEVICE_OBJECT pDevObj; PDEVICE_EXTENSION pDevExt; //创建设备名称 UNICODE_STRING devName; RtlInitUnicodeString(&devName,L"\\Device\\MyDDKDevice"); //创建设备 status = IoCreateDevice( pDriverObject, sizeof(DEVICE_EXTENSION), &(UNICODE_STRING)devName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj ); if (!NT_SUCCESS(status)) return status; pDevObj->Flags |= DO_BUFFERED_IO; pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension; pDevExt->pDevice = pDevObj; pDevExt->ustrDeviceName = devName; //创建符号链接 UNICODE_STRING symLinkName; RtlInitUnicodeString(&symLinkName,L"\\??\\HelloDDK"); pDevExt->ustrSymLinkName = symLinkName; status = IoCreateSymbolicLink( &symLinkName,&devName ); if (!NT_SUCCESS(status)) { IoDeleteDevice( pDevObj ); return status; } return STATUS_SUCCESS; } /************************************************************************ * 函数名称:HelloDDKUnload * 功能描述:负责驱动程序的卸载操作 * 参数列表: pDriverObject:驱动对象 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject) { PDEVICE_OBJECT pNextObj; KdPrint(("Enter DriverUnload\n")); pNextObj = pDriverObject->DeviceObject; while (pNextObj != NULL) { PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION) pNextObj->DeviceExtension; //删除符号链接 UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName; IoDeleteSymbolicLink(&pLinkName); pNextObj = pNextObj->NextDevice; IoDeleteDevice( pDevExt->pDevice ); } } /************************************************************************ * 函数名称:HelloDDKDispatchRoutine * 功能描述:对读IRP进行处理 * 参数列表: pDevObj:功能设备对象 pIrp:从IO请求包 * 返回 值:返回状态 *************************************************************************/ #pragma PAGEDCODE NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { KdPrint(("Enter HelloDDKDispatchRoutine\n")); NTSTATUS status = STATUS_SUCCESS; // 完成IRP pIrp->IoStatus.Status = status; pIrp->IoStatus.Information = 0; // bytes xfered IoCompleteRequest( pIrp, IO_NO_INCREMENT ); KdPrint(("Leave HelloDDKDispatchRoutine\n")); return status; }
/************************************************************************ * 文件名称:driver.h * 作 者:Geons * 完成日期:2016年3月26日17:44:19 *************************************************************************/ #pragma once #ifdef __cplusplus extern "C" { #endif #include <NTDDK.h> #ifdef __cplusplus } #endif #define PAGEDCODE code_seg("PAGE") #define LOCKEDCODE code_seg() #define INITCODE code_seg("INIT") #define PAGEDDATA data_seg("PAGE") #define LOCKEDDATA data_seg() #define INITDATA data_seg("INIT") #define arraysize(p) (sizeof(p)/sizeof((p)[0])) typedef struct _DEVICE_EXTENSION { PDEVICE_OBJECT pDevice; UNICODE_STRING ustrDeviceName; //设备名称 UNICODE_STRING ustrSymLinkName; //符号链接名 } DEVICE_EXTENSION, *PDEVICE_EXTENSION; // 函数声明 NTSTATUS CreateDevice (IN PDRIVER_OBJECT pDriverObject); VOID HelloDDKUnload (IN PDRIVER_OBJECT pDriverObject); NTSTATUS HelloDDKDispatchRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp); VOID LookasideTest();
注意:
在用VS进行编译生成SYS时候,注意修改属性中的“链接器”->“常规”->“附加依赖项”,只需要填写“ntoskrnl.lib;wdm.lib;”,不能写多余的,否则驱动无法加载到系统中,会生成额外的不支持的DLL。
如果出现缓冲区异常,修改属性中的C/C++->代码生成->安全检查->否(/GS)
如果使用X86build是不会出现这个报错问题的