我试图确定为什么我的应用程序占用4GB的专用字节。因此,我进行了一次完整的内存转储,并将其加载到windbg中。但是使用!heap -stat -h进行分析会产生奇怪的结果,这些结果不会相加:

0:000> !heap -s
(...)
          Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast
                            (k)     (k)    (k)     (k) length      blocks cont. heap
-------------------------------------------------------------------------------------
000002d0a0000000 00000002 2800804 2780508 2800700   2984  1980   177    0      6   LFH
000002d09fe10000 00008000      64      4     64      2     1     1    0      0
000002d09ff70000 00001002 1342924 1334876 1342820  13042  3342    87    0      0   LFH


好的,我有一个2.8GB的堆和1.34GB的堆。让我们看一下第一个的分配:

0:000> !heap -stat -h 000002d0a0000000
 heap @ 000002d0a0000000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    651 291 - 1035e1  (16.00)
    79c 1df - e3ce4  (14.06)
    28 156d - 35908  (3.31)
    (...)


IIUC,第一行表示块大小0x651(= 1617字节),数字块0x291(= 657),总字节为0x103531(= 1062369字节=〜1MB),占忙字节总数的16%。但是查看摘要,应该有〜2.8GB的忙字节!

另一个差异:

0:000> !heap -stat -h 000002d0a0000000 -grp A
 heap @ 000002d0a0000000
group-by: ALLOCATIONSIZE max-display: 20
    size     #blocks    total     ( %) (percent of total busy bytes)
    a160 1 - a160  (0.62)
    7e50 2 - fca0  (0.97)

0:000> !heap -h 000002d0a0000000
(...)
(509 lines that note allocations with size 7e50, like this one:)
    000002d0a3f48000: 11560 . 07e60 [101] - busy (7e50)


编辑:许多行在末尾也说Internal,而appears to mean HEAP_ENTRY_VIRTUAL_ALLOC-但是带有(7e50)的509行却没有。

我的问题:如何获取!heap -stat -h显示所有分配,以便它们加到!heap -s的输出中?

最佳答案

目前,我只能解释忙碌百分比,但这可能已经有所帮助。它的值有点误导。

虚拟内存是从VirtualAlloc()获取的内存。 C ++堆管理器使用该基本机制从操作系统获取内存。可以提交(准备使用)或保留(可以稍后提交)该虚拟内存。 !heap -s的输出告诉您有关该虚拟内存的堆状态。

因此,我们同意C ++堆管理器可以使用的任何内存都是已提交的内存。 C ++堆管理器将此粗粒度虚拟内存分为更细的块。堆管理器可以分配这些较小的块并释放它们,这取决于malloc() / free()new / delete操作的需要。

当块空闲时,它们不再忙。同时,C ++堆管理器可能决定不将空闲块还给操作系统,因为


不能,因为64k虚拟内存的其他部分仍在使用中
或它不想(内部原因,我们无法确切知道,例如性能原因)


由于空闲部分不算作忙碌,因此与虚拟内存相比,忙碌百分比似乎太高。

根据您的情况,这意味着:


您有2.8 GB的虚拟内存
在堆000002d0a0000000中,您有〜1 MB / 16%= 6.25 MB的内存正在使用,其余的可能在空闲堆块中(可能不是)


下面的示例基于此C ++代码:

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <string>
#include <iomanip>

int main()
{
    HANDLE hHeap = HeapCreate(0, 0x1000000, 0x10000000); // no options, initial 16M, max 256M
    HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS, 511000); // max. allocation size for non-growing heap
    std::cout << "Debug now, handle is 0x" << std::hex << std::setfill('0') << std::setw(sizeof(HANDLE)) << hHeap << std::endl;
    std::string dummy;
    std::getline(std::cin, dummy);
    return 0;
}


唯一的511kB块将被报告为100%,尽管仅占16 MB的1/32:

0:001> !heap -stat -h 009c0000
 heap @ 009c0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    7cc18 1 - 7cc18  (100.00)


要同时查看免费零件,请使用!heap -h <heap> -f

0:001> !heap -h 0x01430000 -f
Index   Address  Name      Debugging options enabled
  3:   01430000
    Segment at 01430000 to 11430000 (01000000 bytes committed)
    Flags:                00001000
    ForceFlags:           00000000
    Granularity:          8 bytes
    Segment Reserve:      00100000
    Segment Commit:       00002000
    DeCommit Block Thres: 00000200
    DeCommit Total Thres: 00002000
    Total Free Size:      001f05c7
    Max. Allocation Size: 7ffdefff
    Lock Variable at:     01430138
    Next TagIndex:        0000
    Maximum TagIndex:     0000
    Tag Entries:          00000000
    PsuedoTag Entries:    00000000
    Virtual Alloc List:   014300a0
    Uncommitted ranges:   01430090
    FreeList[ 00 ] at 014300c4: 01430590 . 0240e1b0
        0240e1a8: 7cc20 . 21e38 [100] - free             <-- no. 1
        02312588: 7f000 . 7f000 [100] - free             <-- no. 2
        [...]
        01430588: 00588 . 7f000 [100] - free             <-- no. 32

    Heap entries for Segment00 in Heap 01430000
         address: psize . size  flags   state (requested size)
        01430000: 00000 . 00588 [101] - busy (587)
        01430588: 00588 . 7f000 [100]
        [...]
        02312588: 7f000 . 7f000 [100]
        02391588: 7f000 . 7cc20 [101] - busy (7cc18)
        0240e1a8: 7cc20 . 21e38 [100]
        0242ffe0: 21e38 . 00020 [111] - busy (1d)
        02430000:      0f000000      - uncommitted bytes.
0:001> ? 7cc18
Evaluate expression: 511000 = 0007cc18


在这里我们看到我有一个256 MB的堆(未提交的240 MB,0x0f000000 +已提交的16 MB,0x01000000)。总结FreeList中的项目,我得到

0:001> ? 0n31 * 7f000 + 21e38
Evaluate expression: 16264760 = 00f82e38


因此,C ++堆管理器将几乎所有内容(〜16 MB)都视为空闲且不忙。 !heap -s在WinDbg 6.2.9200中以这种方式报告16 MB这样的内存:

0:001> !heap -s
LFH Key                   : 0x23e41d0e
Termination on corruption : ENABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast
                    (k)     (k)    (k)     (k) length      blocks cont. heap
-----------------------------------------------------------------------------
004d0000 00000002    1024    212   1024      6     5     1    0      0   LFH
00750000 00001002      64     20     64      9     2     1    0      0
01430000 00001000  262144  16384 262144  15883    32     1    0      0
    External fragmentation  96 % (32 free blocks)
-----------------------------------------------------------------------------


恕我直言,有一个关于保留和提交内存的错误:它应该是262144k虚拟-16384已提交= 245760k保留。

请注意列表长度如何与之前报告的可用块数匹配。

上面仅说明了繁忙百分比。剩下的问题是:您的情况下报告的可用内存与这种情况不匹配。

通常我会说剩余的内存在虚拟块中,即,如MSDN所述的可增长堆,其内存块大于512 kB(32位)或1 MB(64位)。但事实并非如此。

没有有关虚拟块的输出,并且虚拟块的数量报告为0。

生成虚拟块的程序将是

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <string>
#include <iomanip>

int main()
{
    HANDLE hHeap = HeapCreate(0, 0x1000000, 0); // no options, initial 16M, growable
    HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS, 20*1024*1024); // 20 MB, force growing
    std::cout << "Debug now, handle is 0x" << std::hex << std::setfill('0') << std::setw(sizeof(HANDLE)) << hHeap << std::endl;
    std::string dummy;
    std::getline(std::cin, dummy);
    return 0;
}


!heap命令将提及虚拟块:

0:001> !heap -s
LFH Key                   : 0x7140028b
Termination on corruption : ENABLED
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast
                    (k)     (k)    (k)     (k) length      blocks cont. heap
-----------------------------------------------------------------------------
006d0000 00000002    1024    212   1024      6     5     1    0      0   LFH
001d0000 00001002      64     20     64      9     2     1    0      0
Virtual block: 01810000 - 01810000 (size 00000000)
00810000 00001002   16384  16384  16384  16382    33     1    1      0
    External fragmentation  99 % (33 free blocks)
-----------------------------------------------------------------------------


但是,在您的情况下,虚拟块的值为0。也许这在您的WinDbg版本中被报告为“内部”。如果尚未升级,请尝试使用6.2.9200版,以获取与我相同的输出。

关于heap - !heap -stat -h不显示分配,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33738306/

10-13 08:13