PoolMon 示例

本主题包括以下 PoolMon 用法示例:

示例 1:显示和排序 PoolMon 输出

示例 2:显示驱动程序名称

示例 3:检测内存泄漏

示例 4:检查池内存泄漏

示例 5:监视终端服务器会话

示例 1:显示和排序 PoolMon 输出

此示例介绍配置 PoolMon 显示的各种方法。 默认情况下,PoolMon 按标记值按字母数字顺序显示所有内核内存分配。 可以在命令行或 PoolMon 运行时修改显示的排序顺序。

以下命令启动 PoolMon:

poolmon

以下命令启动 PoolMon,并按可用操作数对显示进行排序:

poolmon /f

在 poolmon 运行时,可以使用运行时命令更改显示。 例如,若要按使用的字节数对显示进行排序,请按 b。 若要按每个分配的字节数排序,请按 m

以下命令启动 PoolMon,并仅显示来自非分页池的分配:

poolmon /p

在 PoolMon 运行时,按 p 切换分页池和/或非分页池的分配。

若要启动 PoolMon 并显示具有特定标记的分配的数据,请使用 /i 参数。 以下命令显示具有 AfdB 标记的分配 (afd.sys用于数据缓冲区) 的标记。

poolmon /iAfdB

若要排除具有特定标记的分配,请使用 /x 参数。 以下命令显示没有 AfdB 标记的所有分配:

poolmon /xAfdB

可以使用星号 (*) 和/或问号 (?) 指定一组具有相同字符的标记。 以下命令显示具有以 Afd 开头的池标记的分配,该标记由 afd.sys 使用;

poolmon /iAfd*

PoolMon 启动命令可以包含多个 /i/x 参数。 以下命令显示具有以 Aud 开头的标记和以 抄送开头的四个字符标记的分配,但 CcBc 标记的分配除外:

poolmon /iAud* /iCc?? /xCcBc

还可以按更新之间的值更改对 PoolMon 显示进行排序。 / ( 参数将 PoolMon 置于按更改排序模式。

以下命令显示具有以 Afd 开头的标记的分配,并按分配中的更改进行排序。 它使用 /a 参数按分配数排序, 使用 /) 参数按分配数的更改进行排序。

poolmon /iAfd* /( /a

/ ( 参数和括号键是切换开关。 当 PoolMon 处于按更改排序模式时,它将所有排序命令解释为命令,以便按值中的更改进行排序。 如果再次按括号键,它将按值排序。

示例 2:显示驱动程序名称

可以使用 PoolMon /g 参数显示分配每个池标记的 Windows 组件和常用驱动程序的名称。 如果在具有特定标记的分配中发现问题,此功能可帮助你识别有问题的组件或驱动程序。

组件和驱动程序列在“Mapped_Driver”列中,即显示中最右侧的列。 Mapped_Driver列的数据来自 pooltag.txt,这是随 WDK 一起安装的文件。

以下命令显示以 NtF 开头的标记分配的内存。 (它使用问号字符 () 作为通配符) /g 参数添加Mapped_Driver列。

poolmon /iNtF? /g "C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\triage\pooltag.txt"

还可以将 pooltag.txt 文件复制到 poolmon 所在的同一位置。 这允许使用此用法。

poolmon /iNtF? /g

生成的显示将列出具有 NtF 开头的标记的分配。 显示中最右侧的列Mapped_Driver显示内存是由 NTFS 文件系统的驱动程序ntfs.sys分配的。 在这种情况下,显示更具体,因为pooltag.txt包含 NTFS 分配的源文件。

 Memory:  260620K Avail:   65152K  PageFlts:    85   InRam Krnl: 2116K P:19560K
 Commit: 237688K Limit: 640916K Peak: 260632K            Pool N: 8500K P:33024K
 System pool information
 Tag  Type     Allocs            Frees            Diff   Bytes      Per Alloc  Mapped_Driver

 NtFA Nonp       9112 (   0)      9112 (   0)     0       0 (     0)      0 [ntfs.sys  -  AttrSup.c]
 NtFB Paged      3996 (   0)      3986 (   0)    10  252088 (     0)  25208 [ntfs.sys  -  BitmpSup.c]
 NtFC Paged   1579279 (   0)   1579269 (   0)    10     640 (     0)     64 [ntfs.sys  -  Create.c]
 NtFD Nonp         13 (   0)        13 (   0)     0       0 (     0)      0 [ntfs.sys  -  DevioSup.c]
 NtFF Paged      1128 (   0)      1128 (   0)     0       0 (     0)      0 [ntfs.sys  -  FileInfo.c]
 NtFI Nonp        152 (   0)       152 (   0)     0       0 (     0)      0 [ntfs.sys  -  IndexSup.c]
 NtFL Nonp      68398 (   0)     68390 (   0)     8   27280 (     0)   3410 [ntfs.sys  -  LogSup.c]
 NtFS Paged      2915 (   0)      2614 (   0)   301   80192 (     0)    266 [ntfs.sys  -  SecurSup.c]
 NtFa Paged       838 (   0)       829 (   0)     9     288 (     0)     32 [ntfs.sys  -  AllocSup.c]
 NtFd Paged    137696 (   0)    137688 (   0)     8     720 (     0)     90 [ntfs.sys  -  DirCtrl.c]
 NtFf Nonp          2 (   0)         1 (   0)     1      40 (     0)     40 [ntfs.sys  -  FsCtrl.c]
 NtFs Nonp      48825 (   0)     47226 (   0)  1599   64536 (     0)     40 [ntfs.sys  -  StrucSup.c]
 NtFv Paged       551 (   0)       551 (   0)     0       0 (     0)      0 [ntfs.sys  -  ViewSup.c]

Pooltag.txt很广泛,但它并不是 Windows 中使用的所有标记的完整列表。 当显示中显示的标记不包含在pooltag.txt中时,PoolMon 会在标记的“Mapped_Driver”列中显示“未知驱动程序”。

以下示例演示 32 位系统上的此方法。

以下命令使用 /i 参数列出以 MEM 结尾的标记的分配。 /g 参数将驱动程序名称从 pooltag.txt 文件添加到显示中。

poolmon /i?MEM /g

生成的显示列出了标记以 MEM 结尾的分配。 但是,由于pooltag.txt中不包含 MEM 标记,因此“未知驱动程序”显示在Mapped_Driver列中,而不是驱动程序名称。

 Tag  Type        Allocs          Frees      Diff   Bytes      Per Alloc    Mapped_Driver

 1MEM Nonp       1 (   0)         0 (   0)     1    3344 (     0)   3344   Unknown Driver
 2MEM Nonp       1 (   0)         0 (   0)     1    3944 (     0)   3944   Unknown Driver
 3MEM Nonp       3 (   0)         0 (   0)     3     248 (     0)     82   Unknown Driver

以下命令启动 PoolMon。 它使用 /i 参数列出标记以 MEM 结尾的分配。

poolmon /i?MEM 

以下命令列出以 Ip 开头的标记的分配。 它使用 /g 参数,该参数使用 Mapped_Driver 列中pooltag.txt文件的内容。

poolmon /iIp* /g

在生成的显示中,Mapped_Driver列包含来自pooltag.txt文件的数据。

 Memory:  130616K Avail:   23692K  PageFlts:   146   InRam Krnl: 2108K P: 9532K
 Commit: 187940K Limit: 318628K Peak: 192000K            Pool N: 8372K P:13384K
 System pool information
 Tag  Type     Allocs            Frees            Diff   Bytes      Per Alloc  Mapped_Driver

 IpEQ Nonp          1 (   0)         0 (   0)        1    1808 (     0)   1808 [ipsec][ipsec.sys    -  event queue]
 IpFI Nonp         26 (   0)         0 (   0)       26    7408 (     0)    284 [ipsec][ipsec.sys    -  Filter blocks]
 IpHP Nonp          1 (   0)         1 (   0)        0       0 (     0)      0 [ipsec.sys    - IP Security]
 IpIO Nonp          1 (   0)         1 (   0)        0       0 (     0)      0 [ipsec]
 IpLA Nonp          1 (   0)         0 (   0)        1     248 (     0)    248 [ipsec][ipsec.sys    -  lookaside lists]
 IpSH Nonp          1 (   0)         1 (   0)        0       0 (     0)      0 [ipsec.sys    - IP Security]
 IpSI Nonp       1027 (   0)         0 (   0)     1027   53272 (     0)     51 [ipsec][ipsec.sys    - initial allcoations]
 IpTI Nonp          3 (   0)         0 (   0)        3    5400 (     0)   1800 [ipsec][ipsec.sys    -  timers]

示例 3:检测内存泄漏

此示例建议使用 PoolMon 检测内存泄漏的过程。

  1. 使用参数 /p /p 启动 PoolMon (仅显示分页池) 和 /b (按) 字节数排序的分配。

    poolmon /p /p /b
    
  2. 让 PoolMon 运行几个小时。 由于启动 PoolMon 会更改数据,因此它必须在数据可靠之前重新获得稳定状态。

  3. 将 PoolMon 生成的信息保存为屏幕截图,或者将其从命令窗口复制并粘贴到记事本。

  4. 返回到 PoolMon,按 两次 p 键可仅显示来自非分页池的分配。

  5. 在至少两小时内,大约每半小时重复步骤 3 和 4,每次在分页池和非分页池之间切换。

  6. 数据收集完成后,检查 Diff (分配操作减去自由操作) 和字节 (分配的字节数减去每个标记释放) 值的字节数,并注意任何持续增加的字节数。

  7. 接下来,停止 PoolMon,等待几个小时,然后重启 PoolMon。

  8. 检查正在增加的分配,并确定现在是否释放了字节。 可能的原因是尚未释放或大小继续增加的分配。

示例 4:检查池内存泄漏

以下示例演示如何使用 PoolMon 调查可疑打印机驱动程序的池内存泄漏。 在此示例中,PoolMon 显示 Windows 使用 Dsrd 标记收集的有关内存分配的数据。

某些打印机驱动程序在分配图形设备接口时分配 Drsd 标记, (GDI) 对象和关联的内存。 如果打印机驱动程序有对象泄漏,则使用 Drsd 标记分配的内存也会泄漏。

注意 在运行此示例中的步骤之前,请确保所使用的打印机在完成之前不会中断。 否则,结果可能无效。

在命令行中,键入以下内容:

poolmon /iDrsd

此命令指示 PoolMon 显示具有 Drsd 标记的分配信息。 (池标记区分大小写,因此请务必按如下所示键入命令。)

记录 Diff 和 Bytes 列中的值。 在以下示例显示中,Diff 的值为 21,字节数为 17472。

Memory:  130480K Avail:   91856K  PageFlts:  1220   InRam Krnl: 2484K P: 7988K
Commit:  30104K Limit: 248432K Peak:  34028K            Pool N: 2224K P: 8004K
Tag  Type        Allocs           Frees           Diff  Bytes           Per Alloc

Drsd Paged       560 ( 177)       539 ( 171)       21   17472 (  4992)    832 

将作业发送到打印机,等待 Windows 恢复正常,然后记录 Diff 和 Bytes 列的值。

Memory:  130480K Avail:   91808K  PageFlts:  1240   InRam Krnl: 2488K P: 7996K
Commit:  30152K Limit: 248432K Peak:  34052K            Pool N: 2224K P: 8012K
Tag  Type        Allocs           Frees           Diff  Bytes          Per Alloc

Drsd Paged       737 (   0)       710 (   0)       27   22464 (     0)    832  

当打印机驱动程序的内存管理正常工作时,Diff 的值应在打印后返回到其原始值 21。 但是,如前面的输出所示,Diff 的值上升到 27,字节数增加到 22464。 初始输出和后续输出之间的差异意味着在打印过程中泄漏了 6 个 Drsd 块,总共 4992 个字节。

有关详细信息

如果你认为你已识别出泄漏的驱动程序,请转到 Microsoft 支持 网站并在知识库中搜索相关文章,或者如果这是第三方驱动程序,请与供应商联系。

示例 5:监视终端服务器会话

此示例演示从终端服务会话池显示分配的几种方法。 它演示了 使用 /s 命令行参数以及 运行参数的 sTSSessionIDi

以下命令显示来自所有终端服务会话池的分配。 在此示例中,配置为终端服务器的本地计算机承载会话,客户端计算机使用远程桌面功能连接到主机。

poolmon /s

作为响应,PoolMon 显示来自所有会话池的分配。 请注意标头中的“所有会话池信息”标题。

Memory:  523572K Avail:  233036K  PageFlts:   344   InRam Krnl: 1828K P:18380K
Commit: 193632K Limit:1279764K Peak: 987356K            Pool N:14332K P:18644K
All sessions pool information
 Tag  Type     Allocs            Frees            Diff   Bytes       Per Alloc

 Bmfd Paged       361 (   0)       336 (   0)       25   57832 (     0)   2313
 DDfb Paged        34 (   0)        22 (   0)       12     720 (     0)     60
 Dddp Paged         8 (   0)         6 (   0)        2     272 (     0)    136
 Dh 1 Paged        24 (   0)        24 (   0)        0       0 (     0)      0
 Dh 2 Paged       344 (   0)       344 (   0)        0       0 (     0)      0
 Dvgr Paged         2 (   0)         2 (   0)        0       0 (     0)      0
 GDev Paged       108 (   0)       102 (   0)        6   20272 (     0)   3378
 GFil Paged        29 (   0)        27 (   0)        2     160 (     0)     80
 GPal Paged        11 (   0)         8 (   0)        3     816 (     0)    272
 GTmp Paged     88876 (   1)     88876 (   1)        0       0 (     0)      0
 GUma Paged         2 (   0)         2 (   0)        0       0 (     0)      0
 Galp Paged      3250 (   0)      3250 (   0)        0       0 (     0)      0
 Gbaf Paged      9829 (   0)      9801 (   0)       28   19712 (     0)    704
 Gcac Paged      3761 (   0)      3706 (   0)       55  288968 (     0)   5253
 Gcsl Paged         1 (   0)         0 (   0)        1     488 (     0)    488
 Gdbr Paged      6277 (   0)      6271 (   0)        6    1872 (     0)    312
 ...

若要查看来自特定会话池的分配,请在 /s 参数后面键入会话 ID,如以下命令所示。 此命令显示终端服务会话 0 的会话池分配。

poolmon /s0

作为响应,PoolMon 显示来自终端服务会话 0 的会话池的分配。 请注意标头中的“会话 0 池信息”标题。

Memory:  523572K Avail:  233024K  PageFlts:   525   InRam Krnl: 1828K P:18384K
 Commit: 193760K Limit:1279764K Peak: 987356K            Pool N:14340K P:18644K
 Session 0 pool information
 Tag  Type     Allocs            Frees            Diff   Bytes       Per Alloc

 Bmfd Paged       361 (   0)       336 (   0)       25   57832 (     0)   2313
 DDfb Paged        34 (   0)        22 (   0)       12     720 (     0)     60
 Dddp Paged         8 (   0)         6 (   0)        2     272 (     0)    136
 Dh 1 Paged        24 (   0)        24 (   0)        0       0 (     0)      0
 Dh 2 Paged       344 (   0)       344 (   0)        0       0 (     0)      0
 Dvgr Paged         2 (   0)         2 (   0)        0       0 (     0)      0
 GDev Paged       108 (   0)       102 (   0)        6   20272 (     0)   3378
 GFil Paged        29 (   0)        27 (   0)        2     160 (     0)     80
 GPal Paged        11 (   0)         8 (   0)        3     816 (     0)    272
 GTmp Paged     89079 (  99)     89079 (  99)        0       0 (     0)      0
 GUma Paged         2 (   0)         2 (   0)        0       0 (     0)      0
 Galp Paged      3250 (   0)      3250 (   0)        0       0 (     0)      0
 Gbaf Paged      9830 (   0)      9802 (   0)       28   19712 (     0)    704
 Gcac Paged      3762 (   0)      3707 (   0)       55  283632 (     0)   5156
 Gcsl Paged         1 (   0)         0 (   0)        1     488 (     0)    488
 Gdbr Paged      6280 (   0)      6274 (   0)        6    1872 (     0)    312
 ...

若要帮助确定哪些驱动程序和组件正在从会话池分配内存,请添加 /g 参数,如以下命令所示。 /g 参数添加一个Mapped_Driver列,其中列出了分配每个标记的 Windows 组件和驱动程序。

poolmon /s0 /g

Memory:  523572K Avail:  235876K  PageFlts:    43   InRam Krnl: 1900K P:18860K
Commit: 185040K Limit:1279764K Peak: 987356K            Pool N:14684K P:19124K
Session 0 pool information
Tag  Type     Allocs            Frees            Diff   Bytes      Per Alloc  Mapped_Driver

Bmfd Paged       421 (   0)       396 (   0)       25   57832 (     0)   2313 [Font related stuff]
DDfb Paged        34 (   0)        22 (   0)       12     720 (     0)     60 Unknown Driver
Dddp Paged        11 (   0)         6 (   0)        5     392 (     0)     78 Unknown Driver
Dh 1 Paged        37 (   0)        35 (   0)        2     224 (     0)    112 Unknown Driver
Dh 2 Paged       367 (   0)       364 (   0)        3     912 (     0)    304 Unknown Driver
Dvgr Paged         2 (   0)         2 (   0)        0       0 (     0)      0 [vga for risc video driver]
GDev Paged       119 (   0)       113 (   0)        6   20272 (     0)   3378 [Gdi pdev]
GFil Paged        29 (   0)        27 (   0)        2     160 (     0)     80 [Gdi engine descriptor list]
GPal Paged        11 (   0)         8 (   0)        3     816 (     0)    272 [Gdi Objects]
GTmp Paged     98626 (   1)     98626 (   1)        0       0 (     0)      0 [Gdi Objects]
GUma Paged         2 (   0)         2 (   0)        0       0 (     0)      0 [Gdi Objects]
Galp Paged      3250 (   0)      3250 (   0)        0       0 (     0)      0 [Gdi Objects]
Gbaf Paged     10331 (   0)     10305 (   0)       26   18304 (     0)    704 [Gdi Objects]
Gcac Paged      4722 (   0)      4666 (   0)       56  305400 (     0)   5453 [Gdi glyph cache]
Gcsl Paged         1 (   0)         0 (   0)        1     488 (     0)    488 [Gdi string resource script names]
Gdbr Paged      6972 (   0)      6965 (   0)        7    2184 (     0)    312 [Gdi driver brush realization]

还可以在 PoolMon 运行时配置终端服务会话池显示。 下表按键入顺序显示一系列正在运行的命令,以及生成的 PoolMon 显示。

该系列以启动 PoolMon 的命令开头。 当 PoolMon 运行时,所有其他参数都会被键入。

poolmon
结果 说明

s

显示所有会话池。

s

显示系统池。

s 参数在系统池和终端服务会话池之间切换显示。

0

显示会话 0 池。

可以在显示系统池时键入会话 ID。

7

显示会话 7 池。

a

显示会话 7 的池分配,按分配数排序。

所有标准运行参数都对会话池显示有效。

0

显示会话 0 的分配,按分配数排序。

会话和排序选项将保留,直到更改。

s

显示系统池。

s

显示会话 0 的分配,按分配数排序。

保留会话选项。

10ENTER

显示会话 1 分配,然后显示会话 0 分配。

如果没有 i,则只能输入会话 ID 0 到 9。

i

提示输入终端服务器会话 ID。

10

显示会话 10 分配。

i

提示输入终端服务器会话 ID。

若要显示所有会话池,请按 i ,然后按 Enter。

ENTER

显示所有会话池。

只有配置为终端服务器的系统才能从会话池中分配内存。 如果使用 PoolMon 在不是终端服务器的计算机上显示会话池,或者键入 Windows 上不存在的会话 ID,PoolMon 不会显示任何分配。 相反,它只显示包含常规内存数据的标题。

以下命令显示来自所有终端服务会话池的分配:

poolmon /s

下图显示了将 /s 命令提交到运行 Windows XP 但无法配置为终端服务器的计算机时生成的 PoolMon 显示:

 Memory:  260620K Avail:   44956K  PageFlts:   308   InRam Krnl: 2744K P:20444K
 Commit: 185452K Limit: 640872K Peak: 192472K            Pool N: 8112K P:20648K
 All sessions pool information
 Tag  Type     Allocs            Frees            Diff   Bytes       Per Alloc