!heap

The !heap extension displays heap usage information, controls breakpoints in the heap manager, detects leaked heap blocks, searches for heap blocks, or displays page heap information.

This extension supports the segment heap and the NT heap. Use !heap with no parameter to list all heaps and their type.

!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] 

Segment and NT Heap Parameters

These parameters work with Segment and NT heaps.

-s
Specifies that summary information is being requested. If SummaryOptions and StatHeapAddress are omitted, then summary information is displayed for all heaps associated with the current process.

SummaryOptions
Can be any combination of the following options. The SummaryOptions are not case-sensitive. Type !heap -s -? for additional information.

Option Effect

-v

Verifies all data blocks.

-b BucketSize

Specifies the bucket size. The default is 1024 bits.

-d DumpBlockSize

Specifies the bucket size.

-a

Dumps all heap blocks.

-c

Specifies that the contents of each block should be displayed.

-triage [Handle | Address]
Causes the debugger to automatically search for failures in a process's heaps. If a heap handle is specified as an argument, that heap is examined; otherwise, all the heaps are searched for one that contains the given address, and if one is found, it is examined. Using -triage is the only way to validate low-fragmentation heap (LFH) corruption.

-x [-v]
Causes the debugger to search for the heap block containing the specified address. If -v is added, the command will search the entire virtual memory space of the current process for pointers to this heap block.

-l
Causes the debugger to detect leaked heap blocks.

-i Address -h HeapAddress
Displays information about the specified Heap.

Address
Specifies the address to search for.

-?
Displays some brief Help text for this extension in the Debugger Command window. Use !heap -? for generic help, and !heap -p -? for page heap help.

NT Heap Parameters

These parameters work only with the NT Heap.

HeapOptions
Can be any combination of the following options. The HeapOptions values are case-sensitive.

Option Effect

-v

Causes the debugger to validate the specified heap.

Note This option does not detect low fragmentation heap (LFH) corruption. Use -triage instead.

-a

Causes the display to include all information for the specified heap. Size, in this case, is rounded up to the heap granularity. (Running !heap with the -a option is equivalent to running it with the three options -h -f -m, which can take a long time.)

-h

Causes the display to include all non-LFH entries for the specified heap.

-hl

Causes the display to include all the entries for the specified heap(s), including LFH entries.

-f

Causes the display to include all the free list entries for the specified heap.

-m

Causes the display to include all the segment entries for the specified heap.

-t

Causes the display to include the tag information for the specified heap.

-T

Causes the display to include the pseudo-tag entries for the specified heap.

-g

Causes the display to include the global tag information. Global tags are associated with each untagged allocation.

-s

Causes the display to include summary information for the specified heap.

-k

(x86-based targets only) Causes the display to include the stack backtrace associated with each entry.

ValidationOptions
Can be any single one of the following options. The ValidationOptions are case-sensitive.

Option Effect

-D

Disables validate-on-call for the specified heap.

-E

Enables validate-on-call for the specified heap.

-d

Disables heap checking for the specified heap.

-e

Enables heap checking for the specified heap.

-i Heap Address or HeapAddress
Displays information about the specified Heap.

BreakAddress
Specifies the address of a block where a breakpoint is to be set or removed.

-b
Causes the debugger to create a conditional breakpoint in the heap manager. The -b option can be followed by alloc, realloc, or free; this specifies whether the breakpoint will be activated by allocating, reallocating, or freeing memory. If BreakAddress is used to specify the address of the block, the breakpoint type can be omitted. If Heap is used to specify the heap address or heap index, the type must be included, as well as the Tag parameter.

Tag
Specifies the tag name within the heap.

-B
Causes the debugger to remove a conditional breakpoint from the heap manager. The breakpoint type (alloc, realloc, or free) must be specified, and must be the same as that used with the -b option.

StatHeapAddress
Specifies the address of the heap. If this is 0 or omitted, all heaps associated with the current process are displayed.

-p
Specifies that page heap information is being requested. If this is used without any PageHeapOptions, all page heaps will be displayed.

PageHeapOptions
Can be any single one of the following options. The PageHeapOptions are case-sensitive. If no options are specified, then all possible page heap handles will be displayed.

Option Effect

-h Handle

Causes the debugger to display detailed information about a page heap with handle Handle.

-a Address

Causes the debugger to find the page heap whose block contains Address. Full details of how this address relates to full-page heap blocks will be included, such as whether this address is part of a page heap, its offset inside the block, and whether the block is allocated or was freed. Stack traces are included whenever available. When using this option, size is displayed in multiples of the heap allocation granularity.

-t[c|s] [Traces]

Causes the debugger to display the collected traces of the heavy heap users. Traces specifies the number of traces to display; the default is four. If there are more traces than the specified number, the earliest traces are displayed. If -t or -tc is used, the traces are sorted by count usage. If -ts is used, the traces are sorted by size. (The -tc and -ts options are supported in Windows XP only; the -t option is supported only in Windows XP and earlier versions of Windows.)

-fi [Traces]

Causes the debugger to display the most recent fault injection traces. Traces specifies the quantity to be displayed; the default is 4.

-all

Causes the debugger to display detailed information about all page heaps.

-?

Causes the debugger to display page heap help, including a diagram of heap blocks. (These diagrams can also be seen in the following Remarks section.)

Before you can use any !heap -p extension command, the page heap must be enabled for your target process. See details in the following Remarks section.

-srch
Scans all heaps for the given pattern.

Pattern
Specifies a pattern for which to look.

Size
Can be any single one of the following options. This specifies the size of the pattern. The '-' is required.

Option Effect

-b

The pattern is one BYTE in size.

-w

The pattern is one WORD in size.

-d

The pattern is one DWORD in size.

-q

The pattern is one QWORD in size.

If none of the above are specified, then the pattern is assumed to be of the same size as the machine pointer.

-flt
Limits the display to include only heaps with the specified size or size range.

FilterOptions
Can be any single one of the following options. The FilterOptions are case-sensitive.

Option Effect

s Size

Limits the display to include only heaps of the specified size.

r SizeMin SizeMax

Limits the display to include only heaps within the specified size range.

-stat
Displays usage statistics for the specified heap.

-h Handle
Causes usage statistics for only the heap at Handle to be displayed. If Handle is 0 or omitted, then usage statistics for all heaps are displayed.

-grp GroupBy
Reorders the display as specified by GroupBy. The options for GroupBy can be found in the following table.

Option Effect

A

Displays the usage statistics according to allocation size.

B

Displays the usage statistics according to block count.

S

Displays the usage statistics according to the total size of each allocation.

MaxDisplay
Limits the output to only MaxDisplay number of lines.

DLL

Windows XP and later

Ext.dll Exts.dll

Additional Information

For information about heaps, see the following resources:

Book: Microsoft Windows Internals by Mark Russinovich and David Solomon.

Example 11: Enabling Page Heap Verification

Example 12: Using Page Heap Verification to Find a Bug

For information on using the Heap memory process logger, see Example 11: Starting a Private Trace Session

Remarks

This extension command can be used to perform a variety of tasks.

The standard !heap command is used to display heap information for the current process. (This should be used only for user-mode processes. The !pool extension command should be used for system processes.)

The !heap -b and !heap -B commands are used to create and delete conditional breakpoints in the heap manager.

The !heap -l command detects leaked heap blocks. It uses a garbage collector algorithm to detect all busy blocks from the heaps that are not referenced anywhere in the process address space. For huge applications, it can take a few minutes to complete. This command is only available in Windows XP and later versions of Windows.

The !heap -x command searches for a heap block containing a given address. If the -v option is used, this command will additionally search the entire virtual memory space of the current process for pointers to this heap block. This command is only available in Windows XP and later versions of Windows.

The !heap -p command displays various forms of page heap information. Before using !heap -p, you must enable the page heap for the target process. This is done through the Global Flags (gflags.exe) utility. To do this, start the utility, fill in the name of the target application in the Image File Name text box, select Image File Options and Enable page heap, and select Apply. Alternatively, you can start the Global Flags utility from a Command Prompt window by typing gflags /i xxx.exe +hpa, where xxx.exe is the name of the target application.

The !heap -p -t[c|s] commands are not supported beyond Windows XP. Use the UMDH tool provided with the debugger package to obtain similar results.

The !heap -srch command displays those heap entries that contain a certain specified pattern.

The !heap -flt command limits the display to only heap allocations of a specified size.

The !heap -stat command displays heap usage statistics.

Here is an example of the standard !heap command:

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.

Here is an example of the !heap -l command:

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.

The table in this example contains all 21 leaks found.

Here is an example of the !heap -x command:

0:011> !heap 002057b8 -x
## Entry     User      Heap      Segment       Size  PrevSize  Flags

002057a8  002057b0  00170000  00170640        58        58  busy extra

Here is an example of the !heap -x -v command:

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),

In this example, there is a pointer to this heap block at address 0x00205990.

Here is an example of the !heap -flt s command:

0:001>!heap -flt s 0x50

This will display all of the allocations of size 0x50.

Here is an example of the !heap -flt r command:

0:001>!heap -flt r 0x50 0x80

This will display each allocation whose size is between 0x50 and 0x7F.

Here is an example of the !heap -srch command.

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'

The following diagrams show the arrangement of heap blocks.

Light page heap block -- allocated:

 +-----+---------------+---+                                  
 |     |               |   |                                  
 +-----+---------------+---+                                  
    ^         ^          ^                                    
    |         |          8 suffix bytes (filled with 0xA0)    
    |         User allocation (filled with E0 if zeroing not requested) 
    Block header (starts with 0xABCDAAAA and ends with 0xDCBAAAAA) 

Light page heap block -- freed:

 +-----+---------------+---+                                  
 |     |               |   |                                  
 +-----+---------------+---+                                  
    ^         ^          ^                                    
    |         |          8 suffix bytes (filled with 0xA0)    
    |         User allocation (filled with F0 bytes)          
    Block header (starts with 0xABCDAAA9 and ends with 0xDCBAAA9) 

Full page heap block -- allocated:

 +-----+---------+---+-------                                 
 |     |         |   |  ... 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) 

Full page heap block -- freed:

 +-----+---------+---+-------                                 
 |     |         |   |  ... 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) 

To see the stack trace of the allocation or the freeing of a heap block or full page heap block, use dt DPH_BLOCK_INFORMATION with the header address, followed by dds with the block's StackTrace field.