123456

 

Windbg学习19(!heap)

以下以windbg启动calc为调试结果:

1!heap

!heap 扩展显示堆使用信息,控制堆管理器中的断点,检测泄露的堆块,搜索堆块或者显示页堆(page heap)信息。

!heap -h列出当前进程的所有堆:

0:000> !heap -h
Index   Address  Name      Debugging options enabled
  1:   000a0000 
    Segment at 000a0000 to 001a0000 (00003000 bytes committed)
  2:   001a0000 
    Segment at 001a0000 to 001b0000 (00006000 bytes committed)
  3:   001b0000 
    Segment at 001b0000 to 001c0000 (00003000 bytes committed)


!heap -v可以观察堆的分配粒度和解除提交阈值:

0:000> !heap 000a0000 -v
Index   Address  Name      Debugging options enabled
  1:   000a0000 
    Segment at 000a0000 to 001a0000 (00003000 bytes committed)
    Flags:                50000062
    ForceFlags:           40000060
    Granularity:          8 bytes
    Segment Reserve:      00100000
    Segment Commit:       00002000
    DeCommit Block Thres: 00000200
    DeCommit Total Thres: 00002000
    Total Free Size:      000000d1
    Max. Allocation Size: 7ffdefff
    Lock Variable at:     000a0608
    Next TagIndex:        0000
    Maximum TagIndex:     0000
    Tag Entries:          00000000
    PsuedoTag Entries:    00000000
    Virtual Alloc List:   000a0050
    UCR FreeList:        000a0598
    FreeList Usage:      00000000 00000000 00000000 00000000
    FreeList[ 00 ] at 000a0178: 000a2980 . 000a2980   (1 block )

Segment at 000a0000 to 001a0000 (00003000 bytes committed)指明堆的内存范围和提交字节数
Granularity: 8 bytes指明堆块分配粒度

 

由于堆管理器使用HEAP结构来记录和维护堆的管理信息,因此我们把这个结构称为堆的管理结构,因为这个结构总是在每个堆的开始处,因此有时也被称为堆的头结构

下面显示了_HEAP的结构:

:000> dt ntdll!_HEAP 000a0000 
   +0x000 Entry            : _HEAP_ENTRY
   +0x008 Signature        : 0xeeffeeff
   +0x00c Flags            : 0x50000062
   +0x010 ForceFlags       : 0x40000060
   +0x014 VirtualMemoryThreshold : 0xfe00
   +0x018 SegmentReserve   : 0x100000
   +0x01c SegmentCommit    : 0x2000
   +0x020 DeCommitFreeBlockThreshold : 0x200
   +0x024 DeCommitTotalFreeThreshold : 0x2000
   +0x028 TotalFreeSize    : 0xd1
   +0x02c MaximumAllocationSize : 0x7ffdefff
   +0x030 ProcessHeapsListIndex : 1
   +0x032 HeaderValidateLength : 0x608
   +0x034 HeaderValidateCopy : (null) 
   +0x038 NextAvailableTagIndex : 0
   +0x03a MaximumTagIndex  : 0
   +0x03c TagEntries       : (null) 
   +0x040 UCRSegments      : (null) 
   +0x044 UnusedUnCommittedRanges : 0x000a0598 _HEAP_UNCOMMMTTED_RANGE
   +0x048 AlignRound       : 0x17
   +0x04c AlignMask        : 0xfffffff8
   +0x050 VirtualAllocdBlocks : _LIST_ENTRY [ 0xa0050 - 0xa0050 ]
   +0x058 Segments         : [64] 0x000a0640 _HEAP_SEGMENT
   +0x158 u                : __unnamed
   +0x168 u2               : __unnamed
   +0x16a AllocatorBackTraceIndex : 0
   +0x16c NonDedicatedListLength : 1
   +0x170 LargeBlocksIndex : (null) 
   +0x174 PseudoTagEntries : (null) 
   +0x178 FreeLists        : [128] _LIST_ENTRY [ 0xa2980 - 0xa2980 ]
   +0x578 LockVariable     : 0x000a0608 _HEAP_LOCK
   +0x57c CommitRoutine    : (null) 
   +0x580 FrontEndHeap     : 0x000a0688 
   +0x584 FrontHeapLockCount : 0
   +0x586 FrontEndHeapType : 0x1 ''
   +0x587 LastSegmentIndex : 0 ''

Segments字段用来记录堆中包含的所有段,它是一个数组,每个元素都指向一个HEAP_SEGMENT结构的指针,

   +0x058 Segments         : [64] 0x000a0640 _HEAP_SEGMENT

LastSegmentIndex的值加1就是段的总个数:

 +0x587 LastSegmentIndex : 0 ''

说明就一个段:

0:000> dt _HEAP_SEGMENT  0x000a0640 
ntdll!_HEAP_SEGMENT
   +0x000 Entry            : _HEAP_ENTRY
   +0x008 Signature        : 0xffeeffee
   +0x00c Flags            : 0
   +0x010 Heap             : 0x000a0000 _HEAP
   +0x014 LargestUnCommittedRange : 0xfd000
   +0x018 BaseAddress      : 0x000a0000 
   +0x01c NumberOfPages    : 0x100
   +0x020 FirstEntry       : 0x000a0680 _HEAP_ENTRY//第一个堆块
   +0x024 LastValidEntry   : 0x001a0000 _HEAP_ENTRY
   +0x028 NumberOfUnCommittedPages : 0xfd
   +0x02c NumberOfUnCommittedRanges : 1
   +0x030 UnCommittedRanges : 0x000a0588 _HEAP_UNCOMMMTTED_RANGE
   +0x034 AllocatorBackTraceIndex : 0
   +0x036 Reserved         : 0
   +0x038 LastEntryInSegment : 0x000a2978 _HEAP_ENTRY//最后一个堆块


 堆管理器使用_HEAP_ENTRY来描述每个堆块:

0:000> dt _HEAP_ENTRY 0x000a0680 
ntdll!_HEAP_ENTRY
   +0x000 Size             : 0x303//堆块的大小,以分配粒度为单位
   +0x002 PreviousSize     : 8//前一个堆块的大小
   +0x000 SubSegmentCode   : 0x00080303 
   +0x004 SmallTagIndex    : 0x60 '`'
   +0x005 Flags            : 0x7 ''//标志
   +0x006 UnusedBytes      : 0x18 ''//因为补齐而多分配的字节数
   +0x007 SegmentIndex     : 0 ''//这个堆块所在段的序号

其中Flags字段代表堆块的状态,其值是下列标志位的组合

标志 含义
HEAP_ENTRY_BUSY 01 该块处于占用状态
HEAP_ENTRY_EXTRA_PRESENT 02 该块存在额外的描述
HEAP_ENTRY_FILL_PATTERN 04 使用固定模式填充堆块
HEAP_ENTRY_VIRTUAL_ALLOC 08 虚拟分配
HEAP_ENTRY_LAST_ENTRY 0X10 这是该段的最后一个块

_HEAP_ENTRY的长度固定为8字节长,位于堆块起始处,其后便是堆块的用户数据,也就是说,把HeapAlloc函数

返回的地址减去8,就是这个堆块的_HEAP_ENTRY结构的地址

 



 



 

posted on 2012-05-31 17:14  hgy413  阅读(1202)  评论(0编辑  收藏  举报

导航