【问题标题】:unordered_map: clear() does not release heap on clear() [duplicate]unordered_map:clear() 不会在 clear() 上释放堆 [重复]
【发布时间】:2017-07-20 16:01:25
【问题描述】:

我在 Solaris 10 上使用 g++ 4.9.2 使用 unordered_map,但令人惊讶的是,我发现 clear() 不会释放堆。 这是示例代码:

#include <iostream>
#include <unordered_map>

int main ()
{
  std::unordered_map<long long, long long> mymap;
  mymap.rehash(200000);
  getchar();
  for (int i = 0; i < 2000000; i++) {
    mymap[i] = i*i;
  }
  std::cout << "current bucket_count: " << mymap.bucket_count() << std::endl;
  std::cout << "current size: " << mymap.size() << std::endl;
  getchar();
  mymap.clear();
  std::cout << "current bucket_count: " << mymap.bucket_count() << std::endl;
  std::cout << "current size: " << mymap.size() << std::endl;
  getchar();
  return 0;
}

当程序等待 getchar() 时,我正在观察程序的堆大小。而且,这是通过pmap -x &lt;PID&gt; | grep heap找到的堆快照

1. While waiting on 1st getchar(): `0002C000     792     792     792       - rwx--    [ heap ]`

2. After 1st getchar(): it prints:

    current bucket_count: 3439651
    current size: 2000000
Heap shows while waiting on 2nd getchar():

    0002C000    3920    3920    3920       - rwx--    [ heap ]
    00400000   73728   72272   72272       - rwx--    [ heap ]

3. After 2nd getchar(): it prints:

    current bucket_count: 3439651
    current size: 0
Heap shows while waiting on 2nd getchar():
0002C000    3920    3920    3920       - rwx--    [ heap ]
00400000   73728   72272   72272       - rwx--    [ heap ]

这表明(第 3 步)clear() 对堆没有影响。虽然,文档说,

std::unordered_map::clear
void clear() noexcept;
Clear content
All the elements in the unordered_map container are dropped: their destructors are called, and they are removed from the container, leaving it with a size of 0.

但是,我的堆计数并没有反映这一点。 还有其他方法可以释放 unordered_map 对象占用的堆吗?或者,我应该使用其他东西吗? 请指导如何从 unordered_map 释放内存?

【问题讨论】:

  • 您从“文档”中得到的引用并没有说明释放地图内部使用的内存,只是地图将变为空。它显然是(因为您将大小打印为零)。
  • 我认为您必须了解大小和容量之间存在差异,它不会释放底层数据结构,即使它确实释放了用于包含元素的内存。当您调用 clear 时,它可能会调用析构函数并将某个大小变量设置为 0,但不会释放容器持有的内存。
  • 从操作系统获取内存以返回以响应new 调用,C++ 运行时库在进程结束之前不会释放它。

标签: c++ memory-leaks heap-memory unordered-map dynamic-allocation


【解决方案1】:

您的地图内容已被删除。与磁盘中的文件类似(仅从索引中删除)。如果下次可以使用,释放内存就没有效果了。

如果你不会真正释放地图内存,你需要销毁整个对象。或者您可以尝试使用零调用void reserve( size_type count );。 (没试过)

【讨论】:

  • reserve(0) 可能不起作用,因为它不具有约束力,并且保留值会小于容量。
【解决方案2】:

unordered_map: clear() 不会在 clear() 上释放堆

C++ 标准不要求clear 释放内存。

但是,我的堆数并没有反映出来。

文档没有提到堆。元素的析构函数被调用,正如您所确认的,大小为 0。如果您添加新元素,它们可能会重用之前清除的元素使用的内存。

还有其他方法可以释放 unordered_map 对象占用的堆吗?

销毁地图肯定会释放其所有内存。

mymap.rehash(0) 也可能有效。

然而,仅仅因为内存被释放给实现(通过调用free),并不意味着实现一定会释放内存给操作系统。实现可能会决定将内存重用于其他分配(尽管这仅适用于小分配)。

在 C++ 中没有执行此操作的标准方法,但 Linux 提供了一个函数 malloc_trim,它将尝试将已释放的内存从堆顶释放到操作系统。

【讨论】:

    【解决方案3】:

    内存没有被释放,因为地图应该继续使用,直到它超出范围或被删除。对于这个合理的默认用例,重新分配会导致不必要的开销。我的建议:

    • 如果确实不再需要它,请将其范围限制在您需要的地方,分别对具有适当范围的地图使用智能指针。
    • 如果您仍然需要它,但暂时不需要,或者只有更少的元素,swap 它带有一个空的临时地图(随后将被删除)。
    • 显式调用析构函数并在原地重新创建新地图。

    【讨论】:

      猜你喜欢
      • 2017-09-06
      • 1970-01-01
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      • 2011-09-24
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多