当valgrind没有出现任何泄漏时,驻留内存增加

时间:2014-04-15 07:45:37

标签: c++ c

我在C ++程序代码中添加了重启选项。每次重新启动时,我都会看到Resident内存增加,而valgrind没有显示任何泄漏。驻地记忆增加的原因是什么?

1 个答案:

答案 0 :(得分:9)

有几个可能的原因:

  1. 你可能正在增长记忆,但实际上并没有泄漏:像vector<int> v; for(;;) v.push_back(1);这样的东西会在几秒钟内耗尽内存,但根据valgrind的说法不会泄漏。
  2. 堆是你的“res”内存的一部分,所以如果你有一些东西分配x MB的堆内存,然后释放它,除非操作系统实际上需要那个内存用于其他目的,它将作为你的应用程序的一部分保留记忆。 (实际上,它比这复杂得多,但对于这个讨论,这张图片是有效的)。
  3. 堆碎片。如果你在堆中分配和释放东西,并且内存大小变化很大,那么内存确实是“免费的”,但是堆中的块可能太小而无法用于下一次分配,所以“新鲜”的一块堆被切断了。想象一下,你从一块长木头开始,然后把它剪下来适合某个地方,然后将它拆下并再次切割 - 你永远不能让它再次恢复到最大尺寸。 (再次,实际上,它比这复杂得多,但对于这个讨论来说已经足够了)。
  4. 您可能希望使用valgrind,valgrind --tool=massif prog的massif工具来识别#1等数据,其中数据随着时间的推移而逐渐增加。

    编辑: 从链接中的页面:

      

    Massif是一个堆分析器。它测量你的堆内存量   程序使用。这包括有用空间和额外字节   分配用于簿记和对齐目的。它也可以测量   程序堆栈的大小,尽管它没有这样做   默认值。

    mem_heap_extra_B是分配为“填充”和“开销”的字节数。它通常只占总分配大小的一小部分,但如果您有许多非常小的分配,它可以控制堆使用。

    mem_stacks_B是应用程序使用的堆栈字节数(默认情况下,这不会被测量,因为它会大大减慢代码速度)。

    以此程序为例:

    #include <vector>
    
    int main(int argc, char **argv)
    {
        (void)argv;   // Not used. 
    
        const int size = 10000;
    
        std::vector<int*> v(size);
    
        switch (argc)
        {
        case 1:
            for(int i = 0; i < size; i++)
            {
                v[i] = new int;
            };
    
            for(int i = 0; i < size; i++)
            {
                delete v[i];
            };
            break;
    
        case 2:
        {
            int *t = new int [size];
            for(int i = 0; i < size; i++)
            {
                v[i] = t+i;
            };
    
            delete [] t;
            break;
        }
    
        }
    
        return 0;
    }
    

    以下是valgrind --tool=massif ./a.out(代码的case 1:变体)的输出(在高峰使用时):

    time=2872338
    mem_heap_B=120000
    mem_heap_extra_B=200008
    mem_stacks_B=0
    heap_tree=peak
    

    如果我们使用valgrind --tool=massif ./a.out 1运行(代码为case 2:),则在使用高峰时,输出为:

    time=2523909
    mem_heap_B=120000
    mem_heap_extra_B=16
    mem_stacks_B=0
    heap_tree=peak
    

    注意mem_heap_extra_B的不同之处 - 在第一种情况下,它大于实际的堆使用量(因为每4字节分配实际上占用了更多),其中在第二种情况下,额外的字节是只有16,但堆的实际“使用”大小是相同的,120000(这是有道理的,我们有8个字节的10000个指针,每个4个字节的10000个整数)。

    不幸的是,这个程序在堆栈使用方面相当无趣,但如果你使用--stacks=yes,它将显示所用堆栈的字节数,例如:

    time=2222719
    mem_heap_B=120000
    mem_heap_extra_B=16
    mem_stacks_B=528
    

    如果我正在研究Pascal编译器中的mem_stacks_B,那么它会变得更有趣:

     10:mem_stacks_B=0
     18:mem_stacks_B=1576
     26:mem_stacks_B=1368
     34:mem_stacks_B=1368
     42:mem_stacks_B=1576
     50:mem_stacks_B=120
     58:mem_stacks_B=2592
     66:mem_stacks_B=4656
    288:mem_stacks_B=2464
    296:mem_stacks_B=43104
    431:mem_stacks_B=2424
    439:mem_stacks_B=10960
    447:mem_stacks_B=8096
    622:mem_stacks_B=8352
    887:mem_stacks_B=3816
    895:mem_stacks_B=3360
    903:mem_stacks_B=3664
    911:mem_stacks_B=3216
    

    还有很多,但足以表明“堆栈使用量变化很大”。

    正如您所看到的,它有很大差异。不,我没有试图弄清楚当它使用43KB的堆栈时它正在做什么 - 无论如何它并不是真的太过分了。