分配系统空间内存Allocating System-Space Memory

驱动程序可以在其 设备扩展 中使用系统分配的空间,作为特定于设备的信息的全局存储区。Drivers can use system-allocated space within their device extensions as global storage areas for device-specific information. 驱动程序只能使用内核堆栈向其内部例程传递少量数据。Drivers can use only the kernel stack to pass small amounts of data to their internal routines. 某些驱动程序必须分配更多的系统空间内存,通常用于 i/o 缓冲区。Some drivers have to allocate additional, larger amounts of system-space memory, typically for I/O buffers.

若要分配 i/o 缓冲空间,要使用的最佳内存分配例程为 MmAllocateNonCachedMemoryMmAllocateContiguousMemorySpecifyCacheAllocateCommonBuffer (如果驱动程序的设备使用 bus 主机 dma 或系统 DMA 控制器的自动初始化模式) 或 ExAllocatePoolWithTagTo allocate I/O buffer space, the best memory allocation routines to use are MmAllocateNonCachedMemory, MmAllocateContiguousMemorySpecifyCache, AllocateCommonBuffer (if the driver's device uses bus-master DMA or a system DMA controller's auto-initialize mode), or ExAllocatePoolWithTag.

在系统运行时,非分页池通常会成为碎片,因此驱动程序的 DriverEntry 例程应调用这些例程来设置驱动程序所需的任何长期 i/o 缓冲区。Nonpaged pool typically becomes fragmented as the system runs, so a driver's DriverEntry routine should call these routines to set up any long-term I/O buffers the driver needs. 其中的每个例程( ExAllocatePoolWithTag除外)都会分配内存,该内存在处理器的数据缓存行大小) 确定的特定处理器边界 (,以提供最佳性能。Each of these routines, except ExAllocatePoolWithTag, allocates memory that is aligned on a processor-specific boundary (determined by the processor's data-cache-line size) to provide best performance.

驱动程序应尽可能经济地分配 i/o 缓冲区,因为非分页池内存是有限的系统资源。Drivers should allocate I/O buffers as economically as possible, because nonpaged pool memory is a limited system resource. 通常,驱动程序应避免重复调用这些支持例程来请求小于页大小的分配, _ 因为每个小于页大小的分配 _ 还附带用于内部管理分配的池标头。Typically, a driver should avoid calling these support routines repeatedly to request allocations of less than PAGE_SIZE because each allocation that is less than PAGE_SIZE also comes with a pool header that is used to internally manage the allocation.

经济实惠地分配驱动程序缓冲区空间的提示Tips for Allocating Driver Buffer Space Economically

若要经济实惠地分配 i/o 缓冲内存,请注意以下事项:To allocate I/O buffer memory economically, be aware of the following:

  • 每次调用 MmAllocateNonCachedMemoryMmAllocateContiguousMemorySpecifyCache 时,均始终返回系统页面大小的完整多个页面大小,即未分页的系统空间内存,无论请求的分配的大小如何。Each call to MmAllocateNonCachedMemory or MmAllocateContiguousMemorySpecifyCache always returns a full multiple of the system's page size, of nonpaged system-space memory, whatever the size of the requested allocation. 因此,小于一个页面的请求将向上舍入到整页,页面上的所有剩余字节数将会浪费;调用函数的驱动程序无法访问它们,并且其他内核模式代码无法使用这些驱动程序。Therefore, requests for less than a page are rounded up to a full page and any remainder bytes on the page are wasted; they are inaccessible by the driver that called the function and are unusable by other kernel-mode code.

  • AllocateCommonBuffer 的每次调用至少使用一个适配器对象映射寄存器,其中至少映射一个字节,最多可映射一页。Each call to AllocateCommonBuffer uses at least one adapter object map register, which maps at least one byte and at most one page. 有关映射寄存器和使用常见缓冲区的详细信息,请参阅 适配器对象和 DMAFor more information about map registers and using common buffers, see Adapter Objects and DMA.

用 ExAllocatePoolWithTag 分配内存Allocating Memory with ExAllocatePoolWithTag

驱动程序还可以调用ExAllocatePoolWithTag,并为PoolType参数指定以下系统定义的池 _ 类型值之一:Drivers can also call ExAllocatePoolWithTag, specifying one of the following system-defined POOL_TYPE values for the PoolType parameter:

  • PoolType = 对于未存储在设备扩展或控制器扩展中的任何对象或资源非分页池,当驱动程序在 IRQL APC 级别运行时,可能会访问该驱动程序 > _ 。PoolType = NonPagedPool for any objects or resources not stored in a device extension or controller extension that the driver might access while it is running at IRQL > APC_LEVEL.

    对于此PoolType值,如果指定的NumberOfBytes小于或等于页面大小,则ExAllocatePoolWithTag将分配所请求的内存量 _ 。For this PoolType value, ExAllocatePoolWithTag allocates the amount of memory that is requested if the specified NumberOfBytes is less than or equal to PAGE_SIZE. 否则,会浪费上次分配的页上的所有剩余字节数:调用方无法访问这些字节,其他内核模式代码无法使用这些字节。Otherwise, any remainder bytes on the last-allocated page are wasted: inaccessible to the caller and unusable by other kernel-mode code.

    例如,在 x86 上,5 kb 的分配请求 (KB) 返回两个 4 KB 的页面。For example, on an x86, an allocation request of 5 kilobytes (KB) returns two 4-KB pages. 第二页的最后 3 KB 对于调用方或其他调用方不可用。The last 3 KB of the second page is unavailable to the caller or another caller. 为了避免浪费非分页池,驱动程序应该有效地分配多个页面。To avoid wasting nonpaged pool, the driver should allocate multiple pages efficiently. 例如,在这种情况下,驱动程序可能会进行两次分配(一个用于页面 _ 大小,另一个用于 1 KB),分配总共 5 KB。In this case, for example, the driver could make two allocations, one for PAGE_SIZE and the other for 1 KB, to allocate a total of 5 KB.

    注意   从 Windows Vista 开始,系统自动添加额外的内存,因此不需要两个分配。Note  Starting with Windows Vista, the system automatically adds the additional memory so two allocations are unnecessary.

  • PoolType = PagedPool对于始终以 IRQL < = APC 级别进行访问 _ 且不在文件系统写入路径中的内存,PagedPool。PoolType = PagedPool for memory that is always accessed at IRQL <= APC_LEVEL and is not in the file system's write path.

如果ExAllocatePoolWithTag不能分配请求的字节数,则返回NULL指针。ExAllocatePoolWithTag returns a NULL pointer if it cannot allocate the requested number of bytes. 驱动程序应始终检查返回的指针。Drivers should always check the returned pointer. 如果其值为 NULLDriverEntry 例程 (或任何其他返回 NTSTATUS 值的驱动程序例程) 应返回状态 _ _ 资源不足或处理错误条件(如果可能)。If its value is NULL, the DriverEntry routine (or any other driver routine that returns NTSTATUS values) should return STATUS_INSUFFICIENT_RESOURCES or handle the error condition if possible.