使用Lookaside内存
频繁申请和回收内存,会导致在内存上产生大量的内存“空洞”,从 而导致最终无法申请内存。DDK为程序员提供了Lookaside结构来解决这个问题。
频繁地申请内存,会导致一个问题,就是在内存中产生“空洞”。图 5-11显示了这种情况,在内存中先后申请三块内存。最开始可用的内 存是连续的。当某个时刻内存块2被回收以后,如果系统想分配一块略 微大于原先内存块2的内存,这时候原先的内存2就不能被申请成功。 因此,频繁地申请、回收内存会导致在内存上产生大量的内存“空洞”。

如果系统中存在大量的内存“空洞”,即使内存中有大量的可用内 存,也会导致申请内存失败。在操作系统空闲的时候,系统会整理内 存中的“空洞”,将内存中的“空洞”进行合并。
如果驱动程序需要频繁地从内存中申请、回收固定大小的内存,DDK提 供了一种机制来解决这个问题,这就是使用Lookaside对象。 可以将Lookaside对象想象成一个内存容器。在初始的时候,它先向 Windows申请了一块比较大的内存。以后程序员每次申请内存的时候, 不是直接向Windows申请内存,而是向Lookaside对象申请内存。 Lookaside对象会智能地避免产生内存“空洞”。如果Lookaside对象 内部的内存不够用时,它会向操作系统申请更多的内存。当Lookaside 对象内部有大量的未使用的内存时,它会自动让Windows回收一部分内存。总之,Lookaside是一个自动的内存分配容器。通过对Lookaside 对象申请内存,效率要高于直接向Windows申请内存。Lookaside一般 会在以下情况使用:
(1)程序员每次申请固定大小的内存。
(2)申请和回收的操作十分频繁。
如果程序员遇到上述两种情况,可以考虑使用Lookaside对象。驱动程序中的运行效率是程序员必须考虑的问题。
使用Lookaside内存的方法
- 初始化Lookaside结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| _IRQL_requires_max_(DISPATCH_LEVEL) NTKERNELAPI 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 InitializeLookAsideList() { if (__IsLookAsideList == FALSE) { ExInitializeNPagedLookasideList(&__LookAsideList, NULL, NULL, 0, BUFFER_SIZE_MAX, 'XXXX', 0); __IsLookAsideList = TRUE; } }
|
- 向LookAside申请内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| PVOID AllocateBufferFromLookAsideList() { KIRQL CurrentIrql; PVOID VirtualAddress = NULL;
if (__IsLookAsideList == FALSE) return NULL;
CurrentIrql = KeGetCurrentIrql(); if (CurrentIrql > DISPATCH_LEVEL) return NULL;
VirtualAddress = ExAllocateFromNPagedLookasideList(&__LookAsideList); if (VirtualAddress != NULL) { RtlZeroMemory(VirtualAddress, BUFFER_SIZE_MAX); }
return VirtualAddress; }
|
- 从Lookaside中释放内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void FreeBufferToLookAsideList( PVOID VirtualAddress) { KIRQL CurrentIrql;
if (__IsLookAsideList == FALSE) return;
if (VirtualAddress == NULL) return;
CurrentIrql = KeGetCurrentIrql(); if (CurrentIrql > DISPATCH_LEVEL) return;
ExFreeToNPagedLookasideList(&__LookAsideList, VirtualAddress); }
|
- 释放Lookaside结构
1 2 3 4 5 6 7 8
| void UninitializeLookAsideList() { if (__IsLookAsideList == TRUE) { ExDeleteNPagedLookasideList(&__LookAsideList); __IsLookAsideList = FALSE; } }
|