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 检测内存泄漏的过程。
使用参数 /p /p 启动 PoolMon (仅显示分页池) 和 /b (按) 字节数排序的分配。
poolmon /p /p /b
让 PoolMon 运行几个小时。 由于启动 PoolMon 会更改数据,因此它必须在数据可靠之前重新获得稳定状态。
将 PoolMon 生成的信息保存为屏幕截图,或者将其从命令窗口复制并粘贴到记事本。
返回到 PoolMon,按 两次 p 键可仅显示来自非分页池的分配。
在至少两小时内,大约每半小时重复步骤 3 和 4,每次在分页池和非分页池之间切换。
数据收集完成后,检查 Diff (分配操作减去自由操作) 和字节 (分配的字节数减去每个标记释放) 值的字节数,并注意任何持续增加的字节数。
接下来,停止 PoolMon,等待几个小时,然后重启 PoolMon。
检查正在增加的分配,并确定现在是否释放了字节。 可能的原因是尚未释放或大小继续增加的分配。
示例 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 命令行参数以及 运行参数的 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