我试图确定为什么我的应用程序占用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/