我试图确定为什么我的应用程序消耗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
的输出?
答案 0 :(得分:3)
目前我只能解释繁忙的百分比,但这可能已经有所帮助。它的价值有点误导。
虚拟内存是从VirtualAlloc()
获取的内存。 C ++堆管理器使用该基本机制从操作系统获取内存。该虚拟内存可以提交(准备使用)或保留(稍后可以提交)。 !heap -s
的输出告诉您关于该虚拟内存的堆的状态。
所以我们同意C ++堆管理器可以使用的任何内存都是已提交的内存。这个粗粒度虚拟内存被C ++堆管理器拆分为更精细的块。堆管理器可以分配这些较小的块并释放它们,具体取决于malloc()
/ free()
或new
/ delete
操作的需要。
当块变为 free 时,它们不再忙。同时,C ++堆管理器可能决定不将空闲块返回给OS,因为
由于 free 部分不算作 busy ,因此与虚拟内存相比,繁忙百分比似乎过高。
映射到您的案例,这意味着:
000002d0a0000000
中以下示例基于此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)都被认为是免费的而不是忙碌的。在WinDbg 6.2.9200中,!heap -s
以这种方式报告了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保留。
请注意列表长度如何与之前报告的空闲块数相匹配。
以上仅解释繁忙百分比。剩下的问题是:您的案例中报告的可用内存与此方案不匹配。
通常我会说剩下的内存是虚拟块,即大约512 kB(32位)或1 MB(64位)的内存块,如MSDN中提到的可扩展堆。但事实并非如此。
虚拟块没有输出,虚拟块数报告为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.也许这被报告为&#34;内部&#34;在您的WinDbg版本中。如果您尚未升级,请尝试使用版本6.2.9200以获得与我相同的输出。