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 开头的标记和以 Cc 开头的四个字符标记的分配,但 使用 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列中显示“未知驱动程序”。 发生这种情况时,可以使用 /c 参数在 32 位系统上搜索驱动程序 () 并确定它们是否分配标记。 (PoolMon 无法在 64 位版本的 Windows上生成本地标记文件,并且 -c 选项不可用。)

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

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

poolmon /i?MEM /g

生成的显示列出了以 MEM 结尾的标记的分配。 但是,由于 MEM 标记未包含在pooltag.txt中,因此“未知驱动程序”会显示在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

在这种情况下,可以使用 /c 参数编译本地驱动程序的列表及其分配的标记,然后在Mapped_Driver列中显示本地驱动程序的名称。

以下命令启动 PoolMon。 它使用 /i 参数列出以 MEM 结尾的标记的分配,并使用 /c 参数显示分配标记的本地驱动程序。

poolmon /i?MEM /c

如果未指定本地标记文件,PoolMon 找不到localtag.txt文件,则会创建一个文件,如以下屏幕消息所示。

d:\tools\poolmon>poolmon /?MEM /c
PoolMon: No localtag.txt in current directory
PoolMon: Creating localtag.txt in current directory......

生成的显示(使用新创建的localtag.txt文件中的内容)显示Mapped_Driver列中的本地驱动程序名称。

 Memory:  260620K Avail:   57840K  PageFlts:   162   InRam Krnl: 2116K P:19448K
 Commit: 244580K Limit: 640916K Peak: 265416K            Pool N: 8496K P:32904K
 System pool information
 Tag  Type     Allocs            Frees            Diff   Bytes      Per Alloc  Mapped_Driver

 1MEM Nonp          1 (   0)         0 (   0)        1    3344 (     0)   3344 [el90xbc5]
 2MEM Nonp          1 (   0)         0 (   0)        1    3944 (     0)   3944 [el90xbc5]
 3MEM Nonp          3 (   0)         0 (   0)        3     248 (     0)     82 [el90xbc5]

若要显示全面的驱动程序名称,可以在命令中合并 /c/g 参数。 (参数顺序不会更改 output.) 以下命令列出了以 Ip 开头的标记的分配。 它使用 /c 参数,该参数使用Mapped_Driver列中localtag.txt文件的内容和 /g 参数,该参数使用Mapped_Driver列中pooltag.txt文件的内容。

poolmon /iIp* /c /g

在生成的显示中,Mapped_Driver列包含来自localtag.txt和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恢复正常,然后记录差异列和字节列的值。

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

下图显示了 PoolMon 显示,如果 /s 命令已提交到运行Windows XP 的计算机,则无法配置为终端服务器:

 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