!heap
!heap 扩展显示堆使用信息、控制堆管理器中的断点、检测泄漏的堆块、搜索堆块或显示页堆信息。
此扩展支持段堆和 NT 堆。 使用不带参数的 !heap 列出所有堆及其类型。
!heap [HeapOptions] [ValidationOptions] [Heap]
!heap -b [{alloc|realloc|free} [Tag]] [Heap | BreakAddress]
!heap -B {alloc|realloc|free} [Heap | BreakAddress]
!heap -l
!heap -s [SummaryOptions] [StatHeapAddress]
!heap -i HeapAddress
!heap -x [-v] Address
!heap -p [PageHeapOptions]
!heap -srch [Size] Pattern
!heap -flt FilterOptions
!heap -stat [-h Handle [-grp GroupBy [MaxDisplay]]]
!heap [-p] -?
!heap -triage [Handle | Address]
段和 NT 堆参数
这些参数适用于段堆和 NT 堆。
-s
指定正在请求摘要信息。 如果省略 SummaryOptions 和 StatHeapAddress,则会显示与当前进程关联的所有堆的摘要信息。
SummaryOptions
选项可以是以下选项的任意组合。 SummaryOptions 不区分大小写。 键入 !heap -s -? 了解更多信息。
选项 | 效果 |
---|---|
-v |
验证所有数据块。 |
-b BucketSize |
指定存储桶大小。 默认值为 1024 位。 |
-d DumpBlockSize |
指定存储桶大小。 |
-a |
转储所有堆块。 |
-c |
指定应显示的每个块的内容。 |
-triage [Handle | Address]
使调试器自动搜索进程堆中的故障。 如果将堆句柄指定为参数,则会检查该堆;否则,将搜索所有堆,查找包含给定地址的堆;如果找到一个堆,则会对其进行检查。 使用 -triage 是验证低分片堆(LFH)损坏的唯一方法。
-x [-v]
使调试器搜索包含指定地址的堆块。 如果添加了 -v,该命令将搜索当前进程的整个虚拟内存空间,以查找指向此堆块的指针。
-l
导致调试器检测泄漏的堆块。
-i Address -h HeapAddress
显示有关指定堆的信息。
Address
指定要搜索的地址。
-?
在“调试器命令”窗口中显示此扩展的一些简短帮助文本。 使用 !heap -? 获取一般帮助;使用 !heap -p -? 获取页面帮助。
NT 堆参数
这些参数仅适用于 NT 堆。
HeapOptions
选项可以是以下选项的任意组合。 HeapOptions 值区分大小写。
选项 | 效果 |
---|---|
-v |
使调试器验证指定的堆。
注意 此选项不会检测低分片堆(LFH)损坏。 请改用 -triage。
|
-a |
使显示包含指定堆的所有信息。 在这种情况下,大小四舍五入到堆粒度。 (使用 -a 选项运行 !heap 相当于使用三个选项 -h -f -m 运行它,这可能需要很长时间。) |
-h |
使显示包含指定堆的所有非 LFH 条目。 |
-hl |
导致显示包含指定堆的所有条目,包括 LFH 条目。 |
-f |
使显示包含指定堆的所有可用列表条目。 |
-m |
使显示包含指定堆的所有段条目。 |
-t |
使显示包含指定堆的标记信息。 |
-T |
使显示包含指定堆的所有伪标记条目。 |
-g |
导致显示包含全局标记信息。 全局标记与每个未标记的分配相关联。 |
-s |
使显示包含指定堆的摘要信息。 |
-k |
(仅基于 x86 的目标)使显示包含与每个条目关联的堆栈回溯。 |
ValidationOptions
可以是以下任意一个选项。 ValidationOptions 区分大小写。
选项 | 效果 |
---|---|
-D |
对指定的堆禁用调用时验证。 |
-E |
对指定的堆启用调用时验证。 |
-d |
对指定的堆禁用堆检查。 |
-e |
对指定的堆启用堆检查。 |
-i Heap Address 或 HeapAddress
显示有关指定堆的信息。
BreakAddress
指定要设置或删除断点的块的地址。
-b
使调试器在堆管理器中创建条件断点。 -b 选项后跟 alloc、realloc 或 free;这指定是否通过分配、重新分配或释放内存来激活断点。 如果使用 BreakAddress 指定块的地址,则可以省略断点类型。 如果使用 Heap 来指定堆地址或堆索引,则必须包括类型以及 Tag 参数。
Tag
指定堆中的标记名称。
-B
使调试器从堆管理器中删除条件断点。 必须指定断点类型(alloc、realloc 或 free),并且必须跟与 -b 选项一起使用的类型相同。
StatHeapAddress
指定堆的地址。 如果为 0 或省略,则会显示与当前进程关联的所有堆。
-p
指定请求的页堆信息。 如果在不使用任何 PageHeapOptions 的情况下使用此功能,则会显示所有页堆。
PageHeapOptions
可以是以下任意一个选项。 PageHeapOptions 区分大小写。 如果未指定任何选项,将显示所有可能的页堆句柄。
选项 | 效果 |
---|---|
-h Handle |
使调试器显示有关具有句柄 Handle 的页堆的详细信息。 |
-a Address |
使调试器查找其块包含 Address 的页堆。 将包含此地址与整页堆块的关系的完整详细信息,例如此地址是页堆的一部分、块内的偏移量,以及块是已分配还是可用。 每当可用时,都包含堆栈跟踪。 使用此选项时,大小以堆分配粒度的倍数显示。 |
-t[c|s] [Traces] |
使调试器显示大量堆用户的收集跟踪。 Traces 指定要显示的跟踪数;默认值为 4。 如果跟踪数多于指定数字,则显示最早的跟踪。 如果使用 -t 或 -tc,则跟踪按计数使用情况进行排序。 如果使用 -ts,则跟踪按大小排序。 (仅 Windows XP 支持 -tc 和 -ts 选项;-t 选项仅在 Windows XP 和早期版本的 Windows 中受支持。) |
-fi [Traces] |
使调试器显示最新的错误注入跟踪。 Traces 指定要显示的数量;默认值为 4。 |
-all |
使调试器显示有关所有页堆的详细信息。 |
-? |
使调试器显示页堆帮助,包括堆块的关系图。 (以下“备注”部分也显示这些关系图)。 |
在使用任何 !heap -p 扩展命令之前,必须为目标进程启用页堆。 请参阅以下“备注”部分中的详细信息。
-srch
扫描所有堆,查找给定堆。
Pattern
指定要查找的模式。
Size
可以是以下任意一个选项。 这会指定模式的大小。 '-' 为必需项。
选项 | 效果 |
---|---|
-b |
模式的大小为一个 BYTE。 |
-w |
模式的大小为一个 WORD。 |
-d |
模式的大小为一个 DWORD。 |
-q |
模式的大小为一个 QWORD。 |
如果未指定上述任何内容,则假定模式的大小与计算机指针大小相同。
-flt
限制显示仅包含指定大小或大小范围的堆分配。
FilterOptions
可以是以下任意一个选项。 FilterOptions 区分大小写。
选项 | 效果 |
---|---|
s Size |
限制显示仅包含单个大小的堆。 |
r SizeMin SizeMax |
限制显示仅包含指定大小范围内的堆。 |
注意
在更高版本的 !heap 选项中,例如 -flt
可能不再存在。 使用命令行帮助确认可用选项。
-stat
显示指定堆的使用情况统计信息。
-h Handle
导致仅显示 Handle 处堆的使用统计信息。 如果 Handle 为 0 或省略,则显示所有堆的使用情况统计信息。
-grp GroupBy
按 GroupBy 指定的顺序重新排序显示。 可在下表中找到 GroupBy 的选项。
选项 | 效果 |
---|---|
A |
根据分配大小显示使用情况统计信息。 |
B |
根据块计数显示使用情况统计信息。 |
S |
根据每个分配的总大小显示使用情况统计信息。 |
MaxDisplay
将输出限制为仅 MaxDisplay 行数。
DLL
Windows XP 及更高版本 |
Ext.dll Exts.dll |
其他信息
有关这些堆的信息,请参阅以下资源:
手册:Mark Russinovich 和 David Solomon 编写的 Microsoft Windows 内部资料。
有关使用堆内存进程记录器的信息,请参阅示例 11:启动专用跟踪会话
注解
此扩展命令可用于执行各种任务。
标准 !heap 命令用于显示当前进程的堆信息。 (这只应用于用户模式进程。!pool 扩展命令应用于系统进程。)
!heap -b 和 !heap -B 命令用于在堆管理器中创建和删除条件断点。
!heap -l 命令检测泄漏的堆块。 它使用垃圾回收器算法,检测进程地址空间中任何位置未引用的堆的所有繁忙块。 对于大型应用程序,可能需要几分钟才能完成。 此命令仅在 Windows XP 和更高版本的 Windows 中可用。
!heap -x 命令搜索包含给定地址的堆块。 如果使用 -v 选项,此命令将进一步搜索当前进程的整个虚拟内存空间,以查找指向此堆块的指针。 此命令仅在 Windows XP 和更高版本的 Windows 中可用。
!heap -p 命令显示各种形式的页堆信息。 在使用 !heap -p 之前,必须为目标进程启用页堆。 这需要通过 Global Flags Utility (gflags.exe) 完成。 为此,请启动该实用工具,在“映像文件名”文本框中填写目标应用程序的名称,选择“映像文件选项和“启用页堆”,然后选择“应用”。 或者,可以通过键入 gflags /i xxx.exe +hpa,从命令提示符窗口启动 Global Flags Utility,其中 xxx.exe 是目标应用程序的名称。
Windows XP 之外不支持 !heap -p -t[c|s] 命令。 使用调试程序包提供的 UMDH 工具可获取类似的结果。
!heap -srch 命令显示包含特定指定模式的堆条目。
!heap -flt 命令将显示限制为仅指定大小的堆分配。
!heap -stat 命令显示堆使用情况统计信息。
以下是标准 !heap 命令的示例:
0:000> !ntsdexts.heap -a
Index Address Name Debugging options enabled
1: 00250000
Segment at 00250000 to 00350000 (00056000 bytes committed)
Flags: 50000062
ForceFlags: 40000060
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00004000
DeCommit Block Thres:00000400
DeCommit Total Thres:00002000
Total Free Size: 000003be
Max. Allocation Size:7ffddfff
Lock Variable at: 00250b54
Next TagIndex: 0012
Maximum TagIndex: 07ff
Tag Entries: 00350000
PsuedoTag Entries: 00250548
Virtual Alloc List: 00250050
UCR FreeList: 002504d8
128-bit bitmap of free lists
FreeList Usage: 00000014 00000000 00000000 00000000
Free Free
List List
# Head Blink Flink
FreeList[ 00 ] at 002500b8: 002a4378 . 002a4378
0x02 - HEAP_ENTRY_EXTRA_PRESENT
0x04 - HEAP_ENTRY_FILL_PATTERN
Entry Prev Cur 0x10 - HEAP_ENTRY_LAST_ENTRY
Address Size Size flags
002a4370: 00098 . 01c90 [14] - free
FreeList[ 02 ] at 002500c8: 0025cb30 . 002527b8
002527b0: 00058 . 00010 [04] - free
0025cb28: 00088 . 00010 [04] - free
FreeList[ 04 ] at 002500d8: 00269a08 . 0026e530
0026e528: 00038 . 00020 [04] - free
0026a4d0: 00038 . 00020 [06] - free
0026f9b8: 00038 . 00020 [04] - free
0025cda0: 00030 . 00020 [06] - free
00272660: 00038 . 00020 [04] - free
0026ab60: 00038 . 00020 [06] - free
00269f20: 00038 . 00020 [06] - free
00299818: 00038 . 00020 [04] - free
0026c028: 00038 . 00020 [06] - free
00269a00: 00038 . 00020 [46] - free
Segment00 at 00250b90:
Flags: 00000000
Base: 00250000
First Entry: 00250bc8
Last Entry: 00350000
Total Pages: 00000080
Total UnCommit: 00000055
Largest UnCommit:000aa000
UnCommitted Ranges: (1)
002a6000: 000aa000
Heap entries for Segment00 in Heap 250000
0x01 - HEAP_ENTRY_BUSY
0x02 - HEAP_ENTRY_EXTRA_PRESENT
0x04 - HEAP_ENTRY_FILL_PATTERN
0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
0x10 - HEAP_ENTRY_LAST_ENTRY
0x20 - HEAP_ENTRY_SETTABLE_FLAG1
0x40 - HEAP_ENTRY_SETTABLE_FLAG2
Entry Prev Cur 0x80 - HEAP_ENTRY_SETTABLE_FLAG3
Address Size Size flags (Bytes used) (Tag name)
00250000: 00000 . 00b90 [01] - busy (b90)
00250b90: 00b90 . 00038 [01] - busy (38)
00250bc8: 00038 . 00040 [07] - busy (24), tail fill (NTDLL!LDR Database)
00250c08: 00040 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
00250c68: 00060 . 00028 [07] - busy (10), tail fill (NTDLL!LDR Database)
00250c90: 00028 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
00250cf0: 00060 . 00050 [07] - busy (38), tail fill (Objects= 80)
00250d40: 00050 . 00048 [07] - busy (2e), tail fill (NTDLL!LDR Database)
00250d88: 00048 . 00c10 [07] - busy (bf4), tail fill (Objects>1024)
00251998: 00c10 . 00030 [07] - busy (12), tail fill (NTDLL!LDR Database)
...
002525c0: 00030 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
00252620: 00060 . 00050 [07] - busy (38), tail fill (NTDLL!LDR Database)
00252670: 00050 . 00040 [07] - busy (22), tail fill (NTDLL!CSRSS Client)
002526b0: 00040 . 00040 [07] - busy (24), tail fill (Objects= 64)
002526f0: 00040 . 00040 [07] - busy (24), tail fill (Objects= 64)
00252730: 00040 . 00028 [07] - busy (10), tail fill (Objects= 40)
00252758: 00028 . 00058 [07] - busy (3c), tail fill (Objects= 88)
002527b0: 00058 . 00010 [04] free fill
002527c0: 00010 . 00058 [07] - busy (3c), tail fill (NTDLL!LDR Database)
00252818: 00058 . 002d0 [07] - busy (2b8), tail fill (Objects= 720)
00252ae8: 002d0 . 00330 [07] - busy (314), tail fill (Objects= 816)
00252e18: 00330 . 00330 [07] - busy (314), tail fill (Objects= 816)
00253148: 00330 . 002a8 [07] - busy (28c), tail fill (NTDLL!LocalAtom)
002533f0: 002a8 . 00030 [07] - busy (18), tail fill (NTDLL!LocalAtom)
00253420: 00030 . 00030 [07] - busy (18), tail fill (NTDLL!LocalAtom)
00253450: 00030 . 00098 [07] - busy (7c), tail fill (BASEDLL!LMEM)
002534e8: 00098 . 00060 [07] - busy (44), tail fill (BASEDLL!TMP)
00253548: 00060 . 00020 [07] - busy (1), tail fill (Objects= 32)
00253568: 00020 . 00028 [07] - busy (10), tail fill (Objects= 40)
00253590: 00028 . 00030 [07] - busy (16), tail fill (Objects= 48)
...
0025ccb8: 00038 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
0025cd18: 00060 . 00058 [07] - busy (3c), tail fill (NTDLL!LDR Database)
0025cd70: 00058 . 00030 [07] - busy (18), tail fill (NTDLL!LDR Database)
0025cda0: 00030 . 00020 [06] free fill (NTDLL!Temporary)
0025cdc0: 00020 . 00258 [07] - busy (23c), tail fill (Objects= 600)
0025d018: 00258 . 01018 [07] - busy (1000), tail fill (Objects>1024)
0025e030: 01018 . 00060 [07] - busy (48), tail fill (NTDLL!LDR Database)
...
002a4190: 00028 . 00118 [07] - busy (100), tail fill (BASEDLL!GMEM)
002a42a8: 00118 . 00030 [07] - busy (18), tail fill (Objects= 48)
002a42d8: 00030 . 00098 [07] - busy (7c), tail fill (Objects= 152)
002a4370: 00098 . 01c90 [14] free fill
002a6000: 000aa000 - uncommitted bytes.
以下是 !heap -l 命令的示例:
1:0:011> !heap -l
1:Heap 00170000
Heap 00280000
Heap 00520000
Heap 00b50000
Heap 00c60000
Heap 01420000
Heap 01550000
Heap 016d0000
Heap 019b0000
Heap 01b40000
Scanning VM ...
## Entry User Heap Segment Size PrevSize Flags
001b2958 001b2960 00170000 00000000 40 18 busy extra
001b9cb0 001b9cb8 00170000 00000000 80 300 busy extra
001ba208 001ba210 00170000 00000000 80 78 busy extra
001cbc90 001cbc98 00170000 00000000 e0 48 busy extra
001cbd70 001cbd78 00170000 00000000 d8 e0 busy extra
001cbe90 001cbe98 00170000 00000000 68 48 busy extra
001cbef8 001cbf00 00170000 00000000 58 68 busy extra
001cc078 001cc080 00170000 00000000 f8 128 busy extra
001cc360 001cc368 00170000 00000000 80 50 busy extra
001cc3e0 001cc3e8 00170000 00000000 58 80 busy extra
001fe550 001fe558 00170000 00000000 150 278 busy extra
001fe6e8 001fe6f0 00170000 00000000 48 48 busy extra
002057a8 002057b0 00170000 00000000 58 58 busy extra
00205800 00205808 00170000 00000000 48 58 busy extra
002058b8 002058c0 00170000 00000000 58 70 busy extra
00205910 00205918 00170000 00000000 48 58 busy extra
00205958 00205960 00170000 00000000 90 48 busy extra
00246970 00246978 00170000 00000000 60 88 busy extra
00251168 00251170 00170000 00000000 78 d0 busy extra user_flag
00527730 00527738 00520000 00000000 40 40 busy extra
00527920 00527928 00520000 00000000 40 80 busy extra
21 leaks detected.
此示例中的表包含找到的所有 21 个泄漏。
以下是 !heap -x 命令的示例:
0:011> !heap 002057b8 -x
## Entry User Heap Segment Size PrevSize Flags
002057a8 002057b0 00170000 00170640 58 58 busy extra
以下是 !heap -x -v 命令的示例:
1:0:011> !heap 002057b8 -x -v
## 1:Entry User Heap Segment Size PrevSize Flags
002057a8 002057b0 00170000 00170640 58 58 busy extra
Search VM for address range 002057a8 - 002057ff : 00205990 (002057d0),
在此示例中,address 0x00205990 处有指向此堆块的指针。
以下是 !heap -flt s 命令的示例:
0:001>!heap -flt s 0x50
这将显示大小 0x50 的所有分配。
以下是 !heap -flt r 命令的示例:
0:001>!heap -flt r 0x50 0x80
这将显示其大小介于 0x50 和 0x7F 之间的每个分配。
以下是 !heap -srch 命令的示例。
0:001> !heap -srch 77176934
_HEAP @ 00090000
in HEAP_ENTRY: Size : Prev Flags - UserPtr UserSize - state
00099A48: 0018 : 0005 [01] - 00099A50 (000000B8) - (busy)
ole32!CALLFRAME_CACHE<INTERFACE_HELPER_CLSID>::`vftable'
_HEAP @ 00090000
in HEAP_ENTRY: Size : Prev Flags - UserPtr UserSize - state
00099B58: 0018 : 0005 [01] - 00099B60 (000000B8) - (busy)
ole32!CALLFRAME_CACHE<INTERFACE_HELPER_CLSID>::`vftable'
下图显示了堆块的排列方式。
轻型页堆块 - 已分配:
+-----+---------------+---+
| | | |
+-----+---------------+---+
^ ^ ^
| | 8 suffix bytes (filled with 0xA0)
| User allocation (filled with E0 if zeroing not requested)
Block header (starts with 0xABCDAAAA and ends with 0xDCBAAAAA)
轻型页堆块 - 释放:
+-----+---------------+---+
| | | |
+-----+---------------+---+
^ ^ ^
| | 8 suffix bytes (filled with 0xA0)
| User allocation (filled with F0 bytes)
Block header (starts with 0xABCDAAA9 and ends with 0xDCBAAA9)
全页堆块 - 已分配:
+-----+---------+---+-------
| | | | ... N/A page
+-----+---------+---+-------
^ ^ ^
| | 0-7 suffix bytes (filled with 0xD0)
| User allocation (if zeroing not requested, filled
with C0)
Block header (starts with 0xABCDBBBB and ends with 0xDCBABBBB)
整页堆块 - 释放:
+-----+---------+---+-------
| | | | ... N/A page
+-----+---------+---+-------
^ ^ ^
| | 0-7 suffix bytes (filled with 0xD0)
| User allocation (filled with F0 bytes)
Block header (starts with 0xABCDBBA and ends with 0xDCBABBBA)
若要查看分配的堆栈跟踪或释放堆块或整页堆块,请使用 dt DPH_BLOCK_INFORMATION 和标头地址,后跟 dds 和块的 StackTrace 字段。