在ReactOS内存管理里,有一块内存区是非分页内存,也就是这块内存始终保持在系统物理内存里面,不会换到磁盘上。那为什么需要这样做呢?全部使用分页内存不是更简单,更方便吗?肯定不行的,因为IA86的内存管理就决定它不能这样做了,当cpu缺页中断时,就需要操作系统把分页内存换到磁盘上,再把加载数据从磁盘读取回来。如果操作系统使用的内存都是分页内存,那么操作系统就没有办法运行了,因为所需要运行的代码都在磁盘上。在内核的驱动程序,也是有这样的要求。驱动程序在执行时可能需要动态分配内存空间,这时你要决定需要的是可分页还是不可分页的内存。如果你的驱动在运行中访问内存的时候能够经受页错误,那么尽量使用可分页内存。
注意:大多数低层磁盘和网络驱动通常不能使用可分页内存,因为他们的代码常常在较高的IRQL等级执行而不允许页错误。但是,文件系统(通常比磁盘驱动占用更大,更多资源)有时候可从可分页池中分配一些内存。非分页内存在整个系统中是一个有限的资源,其数量依赖于系统使用的类型,和系统可用的物理内存。NT提供下面的例程给内核驱动来分配内存:
ExAllocatePool
ExAllocatePoolWithQuota
ExAllocatePoolWithTag
ExAllocatePoolWithQuotaTag
NonPagedPool 请求分配一个不可分页的内存
PagedPool 请求分配一个可分页的内存
如果你在分配的内存里有任何同步结构的话,决不要分配分页内存。当你的应用访问内存时候可以处理页错误的时候,应该指定这个类型。
NonPagedPoolMustSucceed
在其它方式都失败时,而你又必须立即得到内存的时候可以使用这个标志类型。注意这种类型的内存是极度缺乏的资源,可能不足16K。注意,只有在其它途径都失败的时候才使用,如果分配失败,将会导致系统的bugcheck,错误代码是 MUST_SUCCEED_POOL_EMPTY。
NonPagedPoolCacheAligned 这个标志分配使用数据缓存线的尺寸来在cpu特定的边界对齐的非分页内存。注意这个操作默认是在Intel平台上的 NonPagedPool 分配类型。
PagedPoolCacheAligned 这个标志分配使用数据缓存线的尺寸来在cpu特定的边界对齐的分页内存。
NonPagedPoolCacheAlignedMustSucceed
参考NonPagedPoolMustSucceed 和NonPagedPoolCacheAligned
内存池分配器初始化了一些列表,每个列表包含一种固定大小的块。当你使用上面的函数请求内存时,例程试图分配一个和你请求数量相近的或更大一点的固定大小的块。但是,如果你要求的数量超过一页时,或者超过列表中最大块的大小时,又或者
在预先分配的列表中没有可用的块的时候,VMM就会从任何适当类型的系统可用的内存中分配你请求的数量内存给你。当预先分配的列表空了的时候,VMM会分配至少一页的内存,切分,然后把剩下的数据放进适当的块列表中。但是,当你请求的非分页内存的数量超过PAGE_SIZE时候,内存池分配例程不会切分未使用的部分,这会浪费宝贵的非分页内存。也可以使用 MmAllocateNonCachedMemory 或 MmAllocateContiguousMemory来分配非分页或物理连续内存。它们通常不使用在文件系统或者过滤驱动中,而是用于执行池例程或者其它结构。内核驱动如果重复的分配和释放小块的内存(小于一个PAGE_SIZE),可能导致系统的可用物理内存碎片化。这会给系统带来各种问题,包括降低系统的性能等。有一个方法可以避免系统碎片化,就是预先分配一块合理大小的内存,然后自已管理,在这个预先分配的块中分配和释放小块的内存,但这种方法有可能会浪费核心内存。
在ReactOS的文件/ntoskrnl/mm/pool.c里看到下面的代码:
#001 /*
#002 * @implemented
#003 */
#004 PVOID NTAPI
#005 ExAllocatePool (POOL_TYPE PoolType,ULONG NumberOfBytes)
#006 /*
#007 * FUNCTION: Allocates pool memory of a specified type and returns a pointer
#008 * to the allocated block. This routine is used for general purpose allocation
#009 * of memory
#010 * ARGUMENTS:
#011 * PoolType
#012 * Specifies the type of memory to allocate which can be one
#013 * of the following:
#014 *
#015 * NonPagedPool
#016 * NonPagedPoolMustSucceed
#017 * NonPagedPoolCacheAligned
#018 * NonPagedPoolCacheAlignedMustS
#019 * PagedPool
#020 * PagedPoolCacheAligned
#021 *
#022 * NumberOfBytes
#023 * Specifies the number of bytes to allocate
#024 * RETURNS: The allocated block on success
#025 * NULL on failure
#026 */
#027 {
#028 PVOID Block;
#029
#030 #if defined(__GNUC__)
#031
#032 Block = EiAllocatePool(PoolType,
#033 NumberOfBytes,
#034 TAG_NONE,
#035 (PVOID)__builtin_return_address(0));
#036 #elif defined(_MSC_VER)
#037
#038 Block = EiAllocatePool(PoolType,
#039 NumberOfBytes,
#040 TAG_NONE,
#041 &ExAllocatePool);
#042 #else
#043 #error Unknown compiler
#044 #endif
#045
#046 return(Block);
#047 }