推动Windows的限制:分页和非分页池

在之前的“极限”帖子中,我描述了两个最基本的系统资源,即物理内存虚拟内存这一次我将描述两个基本的内核资源,分页池和非分页池,它们是基于这些资源的,并且直接负责包括最大进程数,同步对象和句柄在内的许多其他系统资源限制。

这是整个推动限制系列的索引。虽然他们可以独立存在,但他们认为你是按顺序阅读的。

推动Windows的限制:物理内存

推动Windows的限制:虚拟内存

推动Windows的限制:分页和非分页池

推动Windows的限制:进程和线程

推动Windows的限制:把手

推动Windows的限制:USER和GDI对象 - 第1部分

推动Windows的限制:USER和GDI对象 - 第2部分

分页和非分页池用作操作系统和设备驱动程序用来存储其数据结构的内存资源。池管理器以内核模式运行,使用系统虚拟地址空间的区域(在虚拟内存中推送限制文章中描述)来分配它所分配的内存。内核的池管理器与在用户模式进程中执行的C运行时和Windows堆管理器类似。由于最小的虚拟内存分配大小是系统页面大小(x86和x64上的4KB)的倍数,因此这些辅助内存管理器将较大的分配划分为较小的内存,以便不浪费内存。

例如,如果一个应用程序想要一个512字节的缓冲区来存储一些数据,堆管理器就会占用它所分配的区域之一,并指出前512字节正在使用,返回一个指向该内存的指针并将剩余的内存在它用来跟踪空闲堆区域的列表中。堆管理器使用*区中的内存来满足后续的分配,该空闲区刚刚开始分配的512字节区域。

非分页池

内核和设备驱动程序使用非分页池来存储系统无法处理页面错误时可能访问的数据。当内核执行中断服务例程(ISR)和延迟过程调用(DPC)(这是与硬件中断相关的功能)时,内核进入这种状态。当内核或设备驱动程序获取自旋锁时,页面错误也是非法的,因为它们是ISR和DPC中唯一可以使用的锁的类型,所以必须用来保护从ISR内部访问的数据结构或DPC和其他ISR或DPC或在内核线程上执行的代码。驱动程序违反这些规则会导致最常见的崩溃代码IRQL_NOT_LESS_OR_EQUAL

因此,非页面缓冲池总是保持在物理内存中,非页面缓冲池虚拟内存被分配物理内存。存储在非分页池中的通用系统数据结构包括表示进程和线程的内核和对象,互斥对象,信号灯和事件等同步对象,表示为文件对象的文件引用以及I / O请求包(IRP)代表I / O操作。

分页池

另一方面,分页池从Windows可以将其存储的数据写入分页文件这一事实中获取名称,从而可以将占用的物理内存重新利用。就像用户模式的虚拟内存一样,当驱动程序或系统引用分页文件中的页面缓冲池内存时,会发生称为页面错误的操作,内存管理器将数据读回物理内存。页面缓冲池的最大使用者,至少在Windows Vista和更高版本上,通常是注册表,因为对注册表项和其他注册表数据结构的引用存储在页面缓冲池中。表示内存映射文件的数据结构(内部称为段)也存储在分页池中。

设备驱动程序使用ExAllocatePoolWithTag API来分配非分页和分页池,指定所需池的类型作为参数之一。另一个参数是一个4字节的标签,驱动程序应该使用这些标签来唯一标识它们分配的内存,这可以成为跟踪泄漏池驱动程序的有用键,稍后我会介绍。

查看分页和非分页池使用情况

有三个性能计数器指示池的使用情况:

  • 池非分页字节
  • 池分页字节(分页池的虚拟大小 - 一些可能被分页)
  • 池分页常驻字节(分页池的物理大小)

但是,这些池的最大大小没有性能计数器。可以使用内核调试器!vm命令查看它们,但是对于Windows Vista和更高版本,在本地内核调试模式下使用内核调试器时,必须以禁用MPEG2播放的调试模式启动系统。

相反,使用Process Explorer来查看当前分配的池大小以及最大值。要查看最大值,您需要配置Process Explorer以使用操作系统的符号文件。首先,安装最新的Windows调试工具包。然后运行Process Explorer并在Options菜单中打开Symbol Configuration对话框,并将其指向Debugging Tools for Windows安装目录中的dbghelp.dll,并将符号路径设置为指向Microsoft的符号服务器:

推动Windows的限制:分页和非分页池

配置完符号后,打开“系统信息”对话框(单击“查看”菜单中的“系统信息”或按Ctrl + I)以查看“内核内存”部分中的池信息。以下是在2GB Windows XP系统上的样子:

推动Windows的限制:分页和非分页池

    2GB 32位Windows XP

非分页池限制

正如我在前一篇文章中提到的,在32位Windows上,系统地址空间默认为2GB。这固有地限制了2GB的非分页池(或任何类型的系统虚拟内存)的上限,但它必须与其他类型的资源(如内核本身,设备驱动程序,系统页表项(PTE)等)共享该空间。和缓存的文件视图。

在Vista之前,32位Windows上的内存管理器会计算在启动时要分配多少地址空间。它的公式考虑了各种因素,主要是系统上物理内存的数量。它分配给非页面缓冲池的数量在512MB的系统上开始为128MB,而稍大于1GB或更多的系统则为256MB。在使用/ 3GB选项引导的系统上,以内核地址空间为代价将用户模式地址空间扩展为3GB,最大非分页池为128MB。前面显示的Process Explorer屏幕截图报告了在没有/ 3GB开关的情况下启动的2GB Windows XP系统上的最大256MB。

32位Windows Vista和更高版本的内存管理器(包括Server 2008和Windows 7(没有32位版本的Windows Server 2008 R2))不会静态分割系统地址; 而是根据不断变化的需求动态地将范围分配给不同类型的内存。但是,对于基于物理内存量的非分页池,它仍然会设置一个最大值,稍微超过物理内存的75%或2GB,以较小者为准。以下是2GB Windows Server 2008系统上的最大值:

推动Windows的限制:分页和非分页池

    2GB 32位Windows Server 2008

64位Windows系统具有更大的地址空间,所以内存管理器可以静态分割它,而不用担心不同的类型可能没有足够的空间。64位Windows XP和Windows Server 2003将最大的非分页池设置为每MB或128GB(略小于400K)。以下是2GB 64位Windows XP系统的屏幕截图:

推动Windows的限制:分页和非分页池 

    2GB 64位Windows XP

64位Windows Vista,Windows Server 2008,Windows 7和Windows Server 2008 R2内存管理器通过设置最大值与32位对应项(如适用 - 如前所述,不存在32位版本的Windows Server 2008 R2)相匹配到大约75%的内存,但他们的上限是128GB而不是2GB。以下是2GB 64位Windows Vista系统的屏幕截图,该系统具有与前面显示的32位Windows Server 2008系统类似的未分页池限制。

推动Windows的限制:分页和非分页池 

    2GB 32位Windows Server 2008

最后,这是8GB 64位Windows 7系统的限制:

推动Windows的限制:分页和非分页池 

    8GB 64位Windows 7

下面是一张总结不同版本的Windows的非分页池限制的表格:

  32位 64位
XP,Server 2003 最高1.2GB RAM:32-256MB 
> 1.2GB RAM:256MB
分钟(〜400K / MB的RAM,128GB)
Vista,Server 2008, 
Windows 7,Server 2008 R2
分(内存的75%,2GB) 分(内存的75%,128GB)
Windows 8,Server 2012 分(内存的75%,2GB) 分(2个RAM,128GB)

分页池限制

内核和设备驱动程序使用分页池来存储任何永远不会从DPC或ISR内部进行访问的数据结构,也不会保留螺旋锁。这是因为页面缓冲池的内容可能存在于物理内存中,或者如果内存管理器的工作集算法决定重新调整物理内存的用途,则会被发送到页面文件,并在需要时再次引用到物理内存中。分页池限制因此主要由内存管理器分配给页面缓冲池的系统地址空间量以及系统提交限制决定。

在32位Windows XP上,根据为其他资源分配了多少地址空间来计算限制,最显着的是系统PTE,其上限为491MB。以前显示的2GB Windows XP系统的限制为360MB,例如:

推动Windows的限制:分页和非分页池

   2GB 32位Windows XP

32位Windows Server 2003为分页池预留更多空间,因此其上限为650MB。

由于32位Windows Vista及更高版本具有动态内核地址空间,因此只需将限制设置为2GB即可。因此,当系统地址空间已满或达到系统提交限制时,分页池将耗尽。

64位Windows XP和Windows Server 2003将其最大值设置为非分页池限制的四倍或128GB,以较小者为准。这里是64位Windows XP系统的屏幕截图,它显示分页池限制是非分页池的四倍:

推动Windows的限制:分页和非分页池 

     2GB 64位Windows XP

最后,64位版本的Windows Vista,Windows Server 2008,Windows 7和Windows Server 2008 R2只需将最大值设置为128GB,从而允许分页池的限制跟踪系统提交限制。以下是64位Windows 7系统的屏幕截图:

推动Windows的限制:分页和非分页池 

    8GB 64位Windows 7

以下是操作系统中分页池限制的总结:

  32位 64位
XP,Server 2003 XP:最高491MB 
Server 2003:最高650MB
分钟(4 *非分页池限制,128GB)
Vista,Server 2008, 
Windows 7,Server 2008 R2
分钟(系统提交限制,2GB) min(系统提交限制,128GB)
Windows 8,Server 2012 分钟(系统提交限制,2GB) 分钟(系统提交限制,384GB)

测试池限制

由于几乎每个内核操作都使用内核池,耗尽它们可能会导致不可预知的结果。如果您想亲眼目睹系统运行缓慢时系统的行为,请使用Notmyfault工具。它有一些选项会导致它泄漏您指定的增量中的非分页或分页池。如果要更改泄漏速率,可以在泄漏时更改泄漏大小,Notmyfault可以在您退出时释放所有泄漏的内存:

推动Windows的限制:分页和非分页池

不要在系统上运行此操作,除非您准备好可能会丢失数据,因为应用程序和I / O操作在池耗尽时将开始失败。如果驱动程序没有正确处理内存不足的情况(这被认为是驱动程序中的错误),则甚至可能会出现蓝屏。Windows硬件质量实验室(WHQL)强调驱动程序使用Windows内置的驱动程序验证程序来确保它们可以容忍游泳池外的情况而不会崩溃,但是您可能有第三方驱动程序没有去通过这样的测试或者有在WHQL测试期间没有被捕获的错误。

我在虚拟机上的各种测试系统上运行Notmyfault,看看它们是如何运行的,没有遇到任何系统崩溃,但确实看到了不稳定的行为。例如,在非分页池在64位Windows XP系统上运行后,尝试启动命令提示符导致此对话框:

推动Windows的限制:分页和非分页池

在已经有命令提示符运行的32位Windows Server 2008系统上,即使非页面缓冲池耗尽之后,更改当前目录和目录列表等简单操作也开始失败:

推动Windows的限制:分页和非分页池

在一个测试系统上,我最终看到这个错误信息表明数据可能已经丢失。我希望你永远不要在真正的系统上看到这个对话!

推动Windows的限制:分页和非分页池

用完页面缓冲池会导致类似的错误。这是在分页池用完之后,尝试从32位Windows XP系统上的命令提示符启动记事本的结果。请注意,Windows未能重新绘制窗口的标题栏以及每次尝试遇到的不同错误:

推动Windows的限制:分页和非分页池

以下是开始菜单的“附件”文件夹无法填充在页面缓冲池外的64位Windows Server 2008系统上:

推动Windows的限制:分页和非分页池

在这里,您可以看到系统提交级别也显示在Process Explorer的“系统信息”对话框中,随着Notmyfault泄漏大块分页池并在2GB 32位Windows Server 2008系统上达到最大值2GB,

推动Windows的限制:分页和非分页池

当池耗尽时,即使系统不可用,Windows也不会简单地崩溃,原因是池耗尽可能是极端工作负载高峰造成的临时情况,之后池被释放,系统恢复正常运行。然而,当一个驱动程序(或者内核)泄漏时,这个条件是永久的,识别泄漏的原因变得很重要。这就是帖子开头描述的泳池标签的起源。

跟踪池泄漏

当您怀疑池泄漏并且系统仍然能够启动其他应用程序时,Windows驱动程序工具包中的一个工具Poolmon会显示按池类型分配的分配数量和未完成字节数,并将标记传递给ExAllocatePoolWithTag 。各种热键使Poolmon按不同的列排序; 要查找泄漏的分配类型,可以使用“b”按字节排序,也可以使用“d”按分配和释放数量之间的差异进行排序。这里是运行在Notmyfault已经泄露了14个分配大约100MB的系统上的Poolmon:

推动Windows的限制:分页和非分页池

在识别出左栏中的有罪标记(在这种情况下,“泄漏”)之后,下一步是找到正在使用它的驱动程序。由于标签存储在驱动器映像中,因此可以通过扫描标签中的驱动程序映像来实现。Sysinternals 字符串实用程序会在您指定的文件中转储可打印的字符串(默认情况下最少为三个字符),而且由于大多数设备驱动程序映像位于%Systemroot%\ System32 \ Drivers目录中,因此可以打开命令提示符,转到该目录并执行“strings * |” findstr <tag>“。找到匹配后,您可以使用Sysinternals Sigcheck实用程序转储驱动程序的版本信息以下是使用“泄漏”查找驱动程序时的过程:

推动Windows的限制:分页和非分页池

如果系统崩溃,并且您怀疑是由于池耗尽,请将崩溃转储文件加载到Windows调试工具包中包含的Windbg调试器中,然后使用!vm命令进行确认。以下是Notmyfault耗尽非分页池的系统上的输出:

推动Windows的限制:分页和非分页池

一旦确认泄漏,使用!poolused命令通过与Poolmon相似的标记来获取池使用情况的视图。默认情况下,poolused显示未排序的摘要信息,因此指定1作为按页面缓冲池使用情况进行排序的选项,以及2按非页面缓冲池使用情况进行排序:

推动Windows的限制:分页和非分页池 

在转储来自的系统上使用字符串来使用您发现导致问题的标签来搜索驱动程序。

到目前为止,在这个博客系列中,我已经介绍了Windows中最基本的限制,包括物理内存,虚拟内存,分页和非分页池。下一次,我将讨论Windows支持的进程和线程数量的限制,这些限制是由这些限制引起的。