【问题标题】:Heap allocation with valgrind使用 valgrind 进行堆分配
【发布时间】:2021-04-23 16:25:06
【问题描述】:
const size_t size = 10000000;
using T = unsigned short[];
vector<unique_ptr<T>> v;
v.resize(size);
for (size_t n = 0; n != size ; ++n) {
  v[n] = make_unique<T>(3);
  for (int i = 0; i!= 3; ++i)
    v[n][i] = rand();
}

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

  1. 我的期望: 10.000.000*(8+2*3) = 140.000.000 字节。每个指针 8 个字节,每个无符号短字节 2 个字节。
  2. “valgrind -- --tool=memcheck”返回的内容: 总堆使用量:10,000,112 次分配,10,000,111 次释放,140,161,828 字节分配
  3. 实际情况: VIRT = 419044,RES = 394180 (KB)。

为什么实际尺寸是 valgrind 显示的 3 倍? 我在 VSL、ubuntu 上运行它。

【问题讨论】:

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

标签: c++ memory valgrind allocation


【解决方案1】:

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

您很容易,但 C++ 库会为您完成所有艰苦的工作。

你很容易:你只需 new 一些任意数量的字节,然后 delete 它,你就完成了。但对于 C++ 库来说,这并不容易。它必须知道每个newed 对象或对象有多大。所以当它们是deleted 时,C++ 库知道刚刚删除了多少内存。当内存中的相邻对象获得deleted 时,分配器也需要意识到这一点,并将两个相邻的deleted 对象组合到一个更大的内存块中,以便它可以潜在地用于@987654329 @ing 一个更大的对象,在稍后的某个时间点。

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

所有这些爵士乐都至少需要一个指针值和一个字节计数值。按分配。一个健壮的内部内存分配器可能希望在某个地方存储一个额外的指针,但让我们从一个指针和一个字节数开始,作为内存分配器的一个极简实现。

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

需要存储、跟踪和堆积到每个分配的开销。因此,考虑到每分配 6 个字节至少有 10 个字节的额外开销,观察到使用 2-3 的预期内存量似乎几乎在球场上。如果字节数在内部被跟踪为 4 个字节,或者如果内存池是双向链表,则需要 另一个 8 个字节(可能是 4字节,如果你幸运的话)混在一起。

【讨论】:

    【解决方案2】:

    Valgrind 只是报告它在拦截对 mallocnew 的调用时看到的内容。

    如果您真的想查看使用了多少内存,请尝试massif,也可以尝试使用--pages-as-heap=yes 的massif。该参数还会导致 massif 记录映射为 mmap 的页面。

    【讨论】:

      猜你喜欢
      • 2011-02-10
      • 2021-06-22
      • 2014-09-20
      • 1970-01-01
      • 2021-09-10
      • 1970-01-01
      • 2023-03-20
      • 2016-10-21
      • 2020-05-27
      相关资源
      最近更新 更多