Windows程序具有较大的本机堆,比所有分配大得多

时间:2014-11-09 13:39:37

标签: windows memory memory-management heap-memory

我们在Win 7 64位上运行混合模式进程(托管+非托管)。

我们的进程占用了太多内存(尤其是VM)。根据我们的分析,大部分内存由大型本机堆使用。我们的理论是 LFH在已提交的内存中保存了太多空闲块,以便将来进行分配。它们总和大约1.2 GB,而我们实际分配的本机内存最多只有0.6 GB。

这些数字来自该过程的测试运行。在生产中,它有时会超过10 GB的VM - 已知分配可能有6 GB未计入。

我们想知道这种过度承诺但免费分配的理论是否属实,以及如何减少浪费。

以下是我们分析的详细信息。

  1. 首先,我们需要弄清楚分配的内容并排除内存泄漏。我们运行了Jelle van der Beek的优秀Heap Inspector,我们排除了泄漏,并确定已知的分配最多为0.6 deci-GB。

  2. 我们采用了完整的内存转储并在WinDbg中打开。

  3. !heap -stat 它报告了一个具有1.83 deci-GB提交内存的大型本机堆。远远超过我们的分配总和!

  4. 
    _HEAP 000000001b480000
         Segments            00000078
             Reserved  bytes 0000000072980000
             Committed bytes 000000006d597000
         VirtAllocBlocks     0000001e
             VirtAlloc bytes 0000000eb7a60118
    
    1. 然后我们运行了!heap -stat -h 0000001b480000
    2. 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。

      1. 我们运行了!heap -h 1b480000
      2. ...
        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的块。这些不符合我们所知的分配。还有其他尺寸的神秘块。

        1. 我们跑了!heap -p -all。这会报告LFH内部细分,但我们并不完全理解。上一个报告中的那些3fff0大小的块出现在带有星号标记的LFH报告中,有时候很忙,有时候是Free。然后在他们内部我们看到许多较小的自由块。
        2. 我们猜这些免费区块是合法的。它们是LFH为未来分配预留的VM。但是为什么它们的总大小远远大于内存分配的总和,这可以减少吗?

1 个答案:

答案 0 :(得分:0)

好吧,我可以回答我自己的问题。

我们的计划中已经进行了大量的小额分配和解除分配。没有泄漏,但它似乎以某种方式创造了某种碎片。在整合并消除大部分这些分配之后,我们的软件运行得更好并且使用更少的峰值内存。为什么峰值提交内存比实际使用的峰值内存高得多,这仍然是一个谜。