为什么你的stream程的私有空间比你创build的分配数量要大得多呢?

我想了解我维护的程序的内存使用情况。 我已经意识到,从stream程转储我可以使用windbg做“堆-a 0”来打印我的进程尚未删除的每一个分配。 每个分配看起来有点像:

0000000006a905c0:000a0。 000a0 [07] – 繁忙(68),尾部填充 – 无法在0000000006a90650处读取堆栈条目

在哪里68是我mableced和000a0是多less内存实际使用(因为有一些开销)。

如果我把所有这些分配加到我的程序中,我得到了34Mb,但是这似乎与!address -summary中的内存摘要没有什么关系:

0:000> !address -summary --- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal Free 132 7ff`e905b000 ( 8.000 Tb) 100.00% <unclassified> 1234 0`11025000 ( 272.145 Mb) 74.04% 0.00% Image 430 0`03fe6000 ( 63.898 Mb) 17.38% 0.00% Stack 93 0`01f00000 ( 31.000 Mb) 8.43% 0.00% TEB 31 0`0003e000 ( 248.000 kb) 0.07% 0.00% NlsTables 1 0`00024000 ( 144.000 kb) 0.04% 0.00% ActivationContextData 22 0`0001e000 ( 120.000 kb) 0.03% 0.00% CsrSharedMemory 1 0`00009000 ( 36.000 kb) 0.01% 0.00% PEB 1 0`00001000 ( 4.000 kb) 0.00% 0.00% --- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal MEM_PRIVATE 1340 0`1167d000 ( 278.488 Mb) 75.76% 0.00% MEM_IMAGE 430 0`03fe6000 ( 63.898 Mb) 17.38% 0.00% MEM_MAPPED 43 0`01932000 ( 25.195 Mb) 6.85% 0.00% --- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal MEM_FREE 132 7ff`e905b000 ( 8.000 Tb) 100.00% MEM_RESERVE 631 0`0e970000 ( 233.438 Mb) 63.51% 0.00% MEM_COMMIT 1182 0`08625000 ( 134.145 Mb) 36.49% 0.00% --- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal PAGE_READWRITE 788 0`04428000 ( 68.156 Mb) 18.54% 0.00% PAGE_EXECUTE_READ 85 0`027b8000 ( 39.719 Mb) 10.81% 0.00% PAGE_READONLY 225 0`01984000 ( 25.516 Mb) 6.94% 0.00% PAGE_WRITECOPY 51 0`00081000 ( 516.000 kb) 0.14% 0.00% PAGE_READWRITE|PAGE_GUARD 31 0`0003e000 ( 248.000 kb) 0.07% 0.00% PAGE_EXECUTE_READWRITE 2 0`00002000 ( 8.000 kb) 0.00% 0.00% --- Largest Region by Usage ----------- Base Address -------- Region Size ---------- Free 1`80014000 7fd`cb33c000 ( 7.991 Tb) <unclassified> 0`0eae9000 0`037d7000 ( 55.840 Mb) Image 7ff`7f56e000 0`0062e000 ( 6.180 Mb) Stack 0`04120000 0`000fc000 (1008.000 kb) TEB 7ff`fff7c000 0`00002000 ( 8.000 kb) NlsTables 7ff`fffb0000 0`00024000 ( 144.000 kb) ActivationContextData 0`00130000 0`00005000 ( 20.000 kb) CsrSharedMemory 0`7efe0000 0`00009000 ( 36.000 kb) PEB 7ff`fffdf000 0`00001000 ( 4.000 kb) 

这些数字有些混乱,因为它似乎只有MEM_PRIVATE和MEM_COMMIT的内存才真正被我的程序分配了……剩下的就是共享的DLL和其他区域。 带领我尝试通过执行所有MEM_PRIVATE,MEM_COMMIT段:

!地址-f:VAR,MEM_PRIVATE,MEM_COMMIT

这给每个段的输出,而不是每个malloc …这是一个示例:

  0`12bf0000 0`12bf1000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unclassified> 0`12cf0000 0`12cf5000 0`00005000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unclassified> 0`12e70000 0`12e75000 0`00005000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unclassified> 0`37f20000 0`37f21000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_EXECUTE_READWRITE <unclassified> 0`7ffe0000 0`7ffe1000 0`00001000 MEM_PRIVATE MEM_COMMIT PAGE_READONLY <unclassified> 

第三列是段的大小,如果我把所有这些加到我的程序中,总共得到68Mb(大概是所有分配总和的两倍)。 那么我怎么理顺这两个数字呢? 什么pipe理这些细分市场的规模,为什么总数与我的所有分配差距如此之大? 此外,所有我的分配apears的大小相比,出现在win7任务pipe理器(私人工作集)….所以我错过了一些内存使用的地方?

增加你的分配将不会给你堆使用的总内存“私人内存”。

首先,虚拟内存分配是以64KB的粒度完成的,堆可能使用更大的块。 另外专用内存包括与其他进程不共享(共享)的所有内存。 这包括使用VirtualAlloc分配的内存以及写入时复制页面。

我想我已经用一个小例子程序来重现我的问题,这个程序清楚地显示了正在发生的事情。 我怀疑我的解析器(它使用大量的临时STL对象堆)支持同时分配bigish对象,因为我正在分配更长期的对象:

这里有一个极端的例子,说明如果你用这样的评论来显示什么任务管理器反映出来会发生什么:

  int _tmain(int argc, _TCHAR* argv[]) { void * large_allocs[1024*64]; void * small_allocs[1024*64]; prompt("About to allocate memory"); for (int i = 0; i < _countof(large_allocs); i++) { AllocateNBytes(&large_allocs[i], 10 * 1024); AllocateNBytes(&small_allocs[i], 1); } prompt("\Large and small allocations performed"); //NOTE: Task manager shows 650Mb usage at this point for (int i = 0; i < _countof(large_allocs); i++) free(large_allocs[i]); prompt("Large allocations cleared down, We now only have 64k allocated, but how big is our committed memory?"); //NOTE: Task manager shows windows taking ages to deal with the fragmented memory, it eventually stops with the memory around 226Mb // for committed and private working set despite now only having 64k of real allocations... It doesn't seem to be able to clear down any // further than this... for (int i = 0; i < _countof(small_allocs); i++) free(small_allocs[i]); prompt("Small allocations now cleared down, Notice that the private working set and committed memory take ages to get back down to 0"); //NOTE: The private working set and committed fall back down to what the program started at but take much longer than if I'd only allocated the // small allocations in the first place. return 0; } void prompt(char * message) { printf ("%s\n", message); char buf[2]; printf ("Press any key...\n"); fgets (buf, 2, stdin); } void AllocateNBytes( void ** ptr, DWORD sizeptr ) { *ptr = malloc ( sizeptr * sizeof(BYTE)); for (DWORD i = 0; i < sizeptr; i++) { ((BYTE *) *ptr)[i] = 0; //Fool the optimiser into thinking we read this if (((BYTE *) *ptr)[i] != 0) { printf("%d", ((BYTE *) *ptr)[i]); } } } 

基本上,我的程序似乎证明,你可以只有少量的内存分配,但有大量的窗口提交/保留内存管理器不能解决如何摆脱,不能使用其他方案。 我想答案是我的短期分配对象应该从一个大的预分配池中分配,然后在解析时间结束之后可以全部抛出。

不,这不是正确的方法。 有一个原因,堆保持这个内存,这是因为重新分配它快得多。 当然,操作系统也会分配任何想要分配的内存。 内存管理器选择保留它,因为它提高了性能。

如果你的程序没有消耗更多的内存而不是你的系统可以容纳的内存,那么你不应该关注内存的使用情况,主要是因为内存的存在会被使用,其次是因为有六十万的实现细节会导致额外的内存使用不理解和删除它们不会使您受益。 由于您使用的是Windows,所以最低要求意味着您几乎必须在一个可以轻松关闭64MB内存的系统上运行。

您可以使用GlobalMemoryStatusEx来确定您正在使用多少虚拟内存。 任务管理器绝对不是内存分析信息的可靠来源。