3.6 动态内存分配

驱动程序经常需要进行动态内存分配。我们曾在第1章中提到,内核的栈相当小,因此任何大块的内存都必须动态分配。

内核为驱动程序提供了两个通用的内存池(内核本身也使用它们)。

  • 分页池—在需要时能够将页面换出的内存池。
  • 非分页池—永远不会换出页面,保证驻留在RAM里的内存池。

很显然,非分页池是一个“更好”的内存池,因为它不会导致页面错误。在本书的后面我们会看到一些需要从非分页池分配的例子。驱动程序要尽可能少地使用非分页池,除非必需。其他任何情况驱动程序都应该使用分页池。POOL_TYPE这个枚举类型表示内存池的类型。这个枚举类型包括很多内存池的“类型”,但是只有三种可以被驱动程序使用:PagedPoolNonPagedPoolNonPagePoolNx(没有执行权限的非分页池)。

表3-4总结了最常用的内核内存池函数。

表3-4 内核内存池分配函数

000

有些函数中的tag参数允许用一个4字节的值为分配的内存做标记。通常这个值由4个ASCII字符组成,用来在逻辑上指明该驱动程序或者它的一部分。这些标记可以用来指内存泄漏—如果发现在驱动程序卸载之后,仍然有带有该驱动程序标记的内存块遗留。从这些内存池分配的内存块(以及各块的标记)可以用WDK的PoolMon工具来查看。也能用我写的PoolMonX工具(可以从http://www.github.com/zodiacon/AllTools下载)。图3-1显示了PoolMonX(v2)的截屏。

000

图3-1 PoolMonX(v2)

下面的代码显示了内存分配和字符串复制过程,用来将传递给DriverEntry的注册表路径保存下来,并在Unload例程中释放。

000