小默

[zz]内存管理

 

#ifdef POOL_TAGGING
   #ifdef ExAllocatePool
   
#undef ExAllocatePool
   
#endif
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'frPD')
#endif


内核模式中的基本堆分配函数ExAllocatePool。调用方式如下:

PVOID p = ExAllocatePool(type, nbytes);

type参数是表3-3中列出的POOL_TYPE枚举常量nbytes要分配的字节数返回值是一个内核模式虚拟地址指针,指向已分配的内存块。如果内存不足,则返回一个NULL指针。如果指定的内存池类型为“must succeed”类型,即NonPagedPoolMustSucceedNonPagedPoolCacheAlignedMustS,那么内存不足将导致一个代码为MUST_SUCCEED_POOL_EMPTY的bug check

注意
驱动程序不应该分配“must succeed”类型内存。驱动程序不应使系统在低内存状态下崩溃。另外,整个系统中仅存在有限的“must succeed”内存。实际上,Microsoft希望他们从来就没有公布过“must succeed”内存类型。

表3-3. ExAllocatePool的内存池类型参数

内存池类型 描述
NonPagedPool 从非分页内存池中分配内存
PagedPool 从分页内存池中分配内存
NonPagedPoolMustSucceed 从非分页内存池中分配内存,如果不能分配则产生bugcheck
NonPagedPoolCacheAligned 从非分页内存池中分配内存,并确保内存与CPU cache对齐
NonPagedPoolCacheAlignedMustS 与NonPagedPoolCacheAligned类似,但如果不能分配则产生bugcheck
PagedPoolCacheAligned 从分页内存池中分配内存,并确保内存与CPU cache对齐

调用ExAllocatePool时的最基本原则是被分配内存块是否可以交换出内存。这取决于驱动程序的哪一部分需要访问这块内存。如果在大于或等于DISPATCH_LEVEL级上使用该内存块,那么必须从非分页池中分配内存。如果你总是在低于DISPATCH_LEVEL级上使用内存块,那么既可以从非分页池中分配内存也可以从分页池中分配内存。

你获得的内存块至少是按8字节边界对齐的。如果把某结构的实例放到分配的内存中,那么编译器赋予结构成员的4或8字节偏移在新内存中也将是4或8字节偏移。但在某些RISC平台上,结构成员可能以双字和四字对齐。出于性能上的考虑,希望内存块能适合处理器cache行的最少可能数,使用XxxCacheAligned类型代码可以达到这个要求。如果请求的内存多于一页,那么内存块将从页的边界开始。

释放内存块

调用ExFreePool可以释放由ExAllocatePool分配的内存块:

ExFreePool((PVOID) p);

你确实需要记录分配的内存以便在该内存不再需要时释放它,因为没有人为你做这些事。例如,在AddDevice函数中,有一个IoRegisterDeviceInterface调用,该函数存在副作用:它分配了一块内存以保存接口名。你有责任在以后释放该内存。

不用说,访问从内核模式内存池中分配来的内存必须格外小心。因为驱动程序代码可能执行在处理器的最高特权模式下,在这里,系统对内存数据没有任何保护。

ExAllocatePoolWithTag

调用ExAllocatePool是从内核模式堆中分配内存的标准方式。另一个函数ExAllocatePoolWithTag,与ExAllocatePool稍有不同,它提供了一个有用的额外特征。当使用ExAllocatePoolWithTag时,系统在你要求的内存外又额外地多分配了4个字节的标签。这个标签占用了开始的4个字节位于返回指针所指向地址的前面。调试时,如果你查看分配的内存块会看到这个标签,它帮助你识别有问题的内存块。例如:

PVOID p = ExAllocatePoolWithTag(PagedPool, 42, 'KNUJ');

在这里,我使用了一个32位整数常量作为标签值。在小结尾的计算机如x86上,组成这个标签的4个字节的顺序与正常拼写相反。

WDM.H中声明的内存分配函数受一个预处理宏POOL_TAGGING控制。WDM.H(NTDDK.H中也是)中无条件地定义了POOL_TAGGING,结果,无标签的函数实际上是宏,它真正执行的是有标签函数并加入标签‘ mdW’(指明为WDM的内存块)。如果在未来版本的DDK中没有定义POOL_TAGGING,那么带标签函数将成为无标签函数的宏。Microsoft现在还没打算改变POOL_TAGGING的设置。

由于POOL_TAGGING宏的存在,当你在程序中调用ExAllocatePool时,最终被调用的将是ExAllocatePoolWithTag。如果你关闭了该宏,自己去调用ExAllocatePool,但ExAllocatePool内部仍旧调用ExAllocatePoolWithTag并带一个‘enoN’(即None)的标签。因此你无法避免产生内存标签。所以你应该明确地调用ExAllocatePoolWithTag并加上一个你认为有意义的标签。实际上,Microsoft强烈鼓励你这样做。



 

posted on 2009-12-29 10:05 小默 阅读(608) 评论(0)  编辑 收藏 引用 所属分类: Windows


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

留言簿(13)

随笔分类(287)

随笔档案(289)

漏洞

搜索

积分与排名

最新评论

阅读排行榜