C++ 使用valgrind的堆分配 const size\u t size=10000000; 使用T=无符号短[]; 向量v; v、 调整大小; 对于(大小n=0;n!=size;++n){ v[n]=使_唯一(3); 对于(int i=0;i!=3;++i) v[n][i]=rand(); }

C++ 使用valgrind的堆分配 const size\u t size=10000000; 使用T=无符号短[]; 向量v; v、 调整大小; 对于(大小n=0;n!=size;++n){ v[n]=使_唯一(3); 对于(int i=0;i!=3;++i) v[n][i]=rand(); },c++,memory,valgrind,allocation,C++,Memory,Valgrind,Allocation,我想测量它使用了多少内存 我所期望的:10.000.000*(8+2*3)=140.000.000字节。每个指针8个字节,每个无符号短指针2个字节 什么“valgrind--tool=memcheck”返回:总堆使用率:10000112 allocs,10000111 frees,140161828字节分配 它实际上是什么:VIRT=419044,RES=394180(KB) 为什么实际尺寸比valgrind显示器大3倍? 我在VSL和ubuntu上运行它。你忘记了内存分配本身的开销。只有new

我想测量它使用了多少内存

  • 我所期望的:10.000.000*(8+2*3)=140.000.000字节。每个指针8个字节,每个无符号短指针2个字节
  • 什么“valgrind--tool=memcheck”返回:总堆使用率:10000112 allocs,10000111 frees,140161828字节分配
  • 它实际上是什么:VIRT=419044,RES=394180(KB)
  • 为什么实际尺寸比valgrind显示器大3倍?
    我在VSL和ubuntu上运行它。

    你忘记了内存分配本身的开销。只有
    new
    /
    delete
    本身:必须有东西跟踪它。某处

    <>你很容易,但是C++库为你做了所有的辛勤工作。< /P> 这样做很简单:只需
    新建
    一些任意数量的字节,然后
    删除
    即可。但它不是那么简单的C++库。它必须知道每个
    新的
    ed对象有多大。因此,当它们是代码>删除< /代码> d时,C++库知道内存被删除了多少。当内存中的相邻对象获得
    delete
    d时,分配器还需要意识到这一点,并将两个相邻的
    delete
    d对象组合到一个更大的内存块中,以便在以后的某个时候,它可以潜在地用于
    新建
    一个更大的对象

    这种复杂性并不是免费的。需要对其进行跟踪和汇总

    所有这些jazz至少需要一个指针值和一个字节计数值。每次分配。一个健壮的内部内存分配器可能希望在某个地方存储一个额外的指针,但是让我们从一个指针和一个字节计数开始,作为内存分配器的最低实现

    您一次分配
    sizeof(unsigned short)*3个
    字节,或按我的计数分配6个字节。在64位平台上,指针需要8字节长。假设您有一个智能内存分配器,它维护一组单独的分配,大小不超过64kb,因此内存字节数只需要2个字节。因此,每次分配的开销为10字节


    这项开销需要存储、跟踪,并在每次分配时累积到。因此,考虑到每分配6个字节至少有10个字节的额外开销,观察预期使用的2-3个内存量似乎是相当合理的。如果字节计数在内部被跟踪为4个字节,或者如果内存池是一个双链接列表,则需要另一个8个字节(如果幸运的话,可能是4个字节)。Valgrind只是报告它在拦截对
    malloc
    new
    的调用时看到的内容


    如果确实要查看正在使用的内存量,请尝试使用
    massif
    ,也可以使用
    --页面尝试massif,并将其作为heap=yes
    。此参数还将导致massif记录使用
    mmap

    Lead映射的页面:(1)指针需要在某个位置注册大小,因为T的边界未知,因此会增加161828个字节;(2) 虽然程序需要一定的内存,但操作系统会为您的进程保留整个页面。@YSC我还应该添加resize(),而不调用make_unique,因为它具有预期的行为。即10M默认元素,具有所需的(8字节)大小。我从未见过页面占用如此多的内存。整个问题都很奇怪。指针向量是连续的,但指向的实际数据(那些短数据)可能分散在虚拟内存中。