培训
PoolMon 示例
本主题包括以下 PoolMon 用法示例:
示例 1:显示和排序 PoolMon 输出
示例 2:显示驱动程序名称
示例 3:检测内存泄漏
示例 4:检查池内存泄漏
示例 5:监视终端服务器会话
此示例介绍配置 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 处于按更改排序模式时,它将所有排序命令解释为命令,以便按值中的更改进行排序。 如果再次按括号键,它将按值排序。
可以使用 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]
此示例建议使用 PoolMon 检测内存泄漏的过程。
使用参数 /p /p 启动 PoolMon (仅显示分页池) 和 /b (按) 字节数排序的分配。
poolmon /p /p /b
让 PoolMon 运行几个小时。 由于启动 PoolMon 会更改数据,因此它必须在数据可靠之前重新获得稳定状态。
将 PoolMon 生成的信息保存为屏幕截图,或者将其从命令窗口复制并粘贴到记事本。
返回到 PoolMon,按 两次 p 键可仅显示来自非分页池的分配。
在至少两小时内,大约每半小时重复步骤 3 和 4,每次在分页池和非分页池之间切换。
数据收集完成后,检查 Diff (分配操作减去自由操作) 和字节 (分配的字节数减去每个标记释放) 值的字节数,并注意任何持续增加的字节数。
接下来,停止 PoolMon,等待几个小时,然后重启 PoolMon。
检查正在增加的分配,并确定现在是否释放了字节。 可能的原因是尚未释放或大小继续增加的分配。
以下示例演示如何使用 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 支持 网站并在知识库中搜索相关文章,或者如果这是第三方驱动程序,请与供应商联系。
此示例演示从终端服务会话池显示分配的几种方法。 它演示了 使用 /s 命令行参数以及 运行参数的 s、 TSSessionID 和 i 。
以下命令显示来自所有终端服务会话池的分配。 在此示例中,配置为终端服务器的本地计算机承载会话,客户端计算机使用远程桌面功能连接到主机。
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