"!heap -flt -s xxxx" windbg 命令中的不同列代表啥

Posted

技术标签:

【中文标题】"!heap -flt -s xxxx" windbg 命令中的不同列代表啥【英文标题】:What do the different columns in the "!heap -flt -s xxxx" windbg command represent"!heap -flt -s xxxx" windbg 命令中的不同列代表什么 【发布时间】:2011-10-04 23:16:59 【问题描述】:

我一直在做一些关于高内存问题的工作,我一直在 windbg 中进行大量堆分析,我很好奇“!heap -flt -s xxxx”命令中不同列的真正含义.

我阅读了What do the 'size' numbers mean in the windbg !heap output?,并查看了我的“Windows Internals”一书,但我仍然有很多问题。所以列和我的问题如下。

**HEAP_ENTRY** - What does this pointer really point to? How is it different than UserPtr?
**Size** - What does this size mean? How is it different than UserSize?
**Prev** - This just appears to be the negative offset to get to the previous heap entry. Still not sure exactly how it's used.
**Flags** - Is there any documentation on these flags?
**UserPtr** - What is the user pointer? In all cases I've seen it's always 8 bytes higher than the HEAP_ENTRY, but I don't really know what it points to.
**UserSize** - This appears to be the size of the actual allocation.
**state** - This just tells you what state of this heap entry is (free, busy, etc....)

Example:
HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
  0015eeb0 0044 0000  [07]   0015eeb8    00204 - (busy)

【问题讨论】:

好问题.. 我也想知道同样的事情 【参考方案1】:

通过查看 Debugging Tools for Windows 帮助文件中的 !heap 文档和 MSDN 上的堆文档以及来自 Advanced Windows Debugging 的出色 excerpt,以下是我能够汇总的内容:

HEAP_ENTRY:指向堆内入口的指针。如您所见,有一个 8 字节的标头,其中包含 HEAP_ENTRY 结构的数据。 HEAP_ENTRY 结构的大小是 8 个字节,它定义了“堆粒度”大小。这用于确定... SIZE:条目的粒度大小(即分配大小/8) FLAGS:这些在 winbase.h 中定义,并在 MSDN 链接中找到解释。 USERPTR:指向已分配(或已释放)对象的实际指针

【讨论】:

【参考方案2】:

嗯,HEAP_ENTRY 和 UserPtr 之间的主要区别在于,堆必须被索引、分配、填充元数据(如分配给用户的长度)......否则,你怎么能释放( p)没有提供分配多少字节的东西?两个大小字段相同:一是索引堆的结构有多大,一是可供用户使用的内存区域有多大。

反过来,FLAGS 基本上指定分配的内存块的哪些属性,如果它被提交或只是保留,并且,我猜,如果需要,内核使用它来重新排列或共享内存区域(但正如 nithins 指定的那样记录在 MSDN 中)。

PREV ptr 用于跟踪所有分配的区域,第一个指针存储在 PEB 结构中,因此用户空间和内核空间代码都知道分配的堆池。

【讨论】:

【参考方案3】:

HEAP_ENTRY 堆将分配的块存储在连续的内存段中,每个分配的块以一个 8 字节的标头开头,后跟实际分配的数据。 HEAP_ENTRY 列是分配块头的开始地址。

尺寸 堆管理器以 8 个字节的倍数处理块。该列是分配的 8 字节块的数量。在您的示例中,0044 表示该块占用 0x220 字节 (0x44*8)。

上一个 乘以 8 得到前一个堆块的负偏移量(以字节为单位)。

标志 这是对以下信息进行编码的位掩码

0x01 - HEAP_ENTRY_BUSY
0x02 - HEAP_ENTRY_EXTRA_PRESENT
0x04 - HEAP_ENTRY_FILL_PATTERN
0x08 - HEAP_ENTRY_VIRTUAL_ALLOC
0x10 - HEAP_ENTRY_LAST_ENTRY

用户指针 这是 HeapAlloc(由 malloc/new 调用)函数返回给应用程序的指针。由于标头始终为 8 字节长,因此始终为 HEAP_ENTRY +8。

用户大小 这是通过 HeapAlloc 函数的大小。

状态 这是对 Flags 列的解码,告诉条目是否忙、已释放、其段的最后一个……

请注意,在 Windows 7/2008 R2 中,堆默认使用名为 LFH(低碎片堆)的前端,该前端使用默认堆管理器来分配块,在其中分派用户分配的数据。对于这些堆,UserPtr 和 UserSize 不会指向真实的用户数据。 !heap -s 的输出显示启用了 LFH 的堆。

【讨论】:

你碰巧知道如何在 LFH 堆中获取真正的 userptr(这就是最初引发这个问题的原因)? !heap -p 了解 LFH,但选择较少。您可以使用 !heap -p -a 从地址获取真正的 userptr。 !heap -p -all 将列出所有堆的所有用户块。如果您在文件中重定向输出,则可以使用 grep 查找所需用户大小的块。 线程已经很老了,但请注意,对于 x64,用户 ptr 位置是 HEAP_ENTRY +16,因为来自 ntdll.dll 的 sizeof(_HEAP_ENTRY) 返回 0x10 / 16 字节。此外,较新版本的 WinDBG 似乎正确地将 UserPtr 映射到数据,尽管我还不知道他们在旧版本中如何或为什么不这样做

以上是关于"!heap -flt -s xxxx" windbg 命令中的不同列代表啥的主要内容,如果未能解决你的问题,请参考以下文章

Webpack打包报"JavaScript heap out of memory"错误

Webpack打包报"JavaScript heap out of memory"错误

2Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

eclipse里报:An internal error occurred during: "Building workspace". Java heap space(内存溢出)(示

算法 Heap sort

easy -heap