我们在Win 7 64位上运行混合模式进程(托管+非托管)。
我们的进程占用了太多内存(尤其是VM)。根据我们的分析,大部分内存由大型本机堆使用。我们的理论是 LFH在已提交的内存中保存了太多空闲块,以便将来进行分配。它们总和大约1.2 GB,而我们实际分配的本机内存最多只有0.6 GB。
这些数字来自该过程的测试运行。在生产中,它有时会超过10 GB的VM - 已知分配可能有6 GB未计入。
我们想知道这种过度承诺但免费分配的理论是否属实,以及如何减少浪费。
以下是我们分析的详细信息。
首先,我们需要弄清楚分配的内容并排除内存泄漏。我们运行了Jelle van der Beek的优秀Heap Inspector,我们排除了泄漏,并确定已知的分配最多为0.6 deci-GB。
我们采用了完整的内存转储并在WinDbg中打开。
跑!heap -stat
它报告了一个具有1.83 deci-GB提交内存的大型本机堆。远远超过我们的分配总和!
_HEAP 000000001b480000 Segments 00000078 Reserved bytes 0000000072980000 Committed bytes 000000006d597000 VirtAllocBlocks 0000001e VirtAlloc bytes 0000000eb7a60118
!heap -stat -h 0000001b480000
heap @ 000000001b480000 group-by: TOTSIZE max-display: 20 size #blocks total ( %) (percent of total busy bytes) c0000 12 - d80000 (10.54) b0000 d - 8f0000 (6.98) e0000 a - 8c0000 (6.83) ...
如果我们将所有20个报告的项目相加,它们总计可达85 deci-MB - 远低于我们正在寻找的1.79 deci-GB。
!heap -h 1b480000
... Flags: 00001002 ForceFlags: 00000000 Granularity: 16 bytes Segment Reserve: 72a70000 Segment Commit: 00002000 DeCommit Block Thres: 00000400 DeCommit Total Thres: 00001000 Total Free Size: 013b60f1 Max. Allocation Size: 000007fffffdefff Lock Variable at: 000000001b480208 Next TagIndex: 0000 Maximum TagIndex: 0000 Tag Entries: 00000000 PsuedoTag Entries: 00000000 Virtual Alloc List: 1b480118 Unable to read nt!_HEAP_VIRTUAL_ALLOC_ENTRY structure at 000000002acf0000 Uncommitted ranges: 1b4800f8 FreeList[ 00 ] at 000000001b480158: 00000000be940080 . 0000000085828c60 (9451 blocks) ...
在报告中添加所有细分受众群时,我们会得到:
Total Size = 1.83 deci-GB
Segments Marked Busy Size = 1.50 deci-GB
Segments Marked Busy and Internal Size = 1.37 deci-GB
因此,此报告中的所有已提交字节都会累计到总提交大小。我们按块大小进行分组,最重的分配来自大小为0x3fff0的块。这些不符合我们所知的分配。还有其他尺寸的神秘块。
!heap -p -all
。这会报告LFH内部细分,但我们并不完全理解。上一个报告中的那些3fff0大小的块出现在带有星号标记的LFH报告中,有时候很忙,有时候是Free。然后在他们内部我们看到许多较小的自由块。 我们猜这些免费区块是合法的。它们是LFH为未来分配预留的VM。但是为什么它们的总大小远远大于内存分配的总和,这可以减少吗?
答案 0 :(得分:0)
好吧,我可以回答我自己的问题。
我们的计划中已经进行了大量的小额分配和解除分配。没有泄漏,但它似乎以某种方式创造了某种碎片。在整合并消除大部分这些分配之后,我们的软件运行得更好并且使用更少的峰值内存。为什么峰值提交内存比实际使用的峰值内存高得多,这仍然是一个谜。