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

unordered_map: clear() does not release heap on clear()

本文关键字:clear 释放 map unordered      更新时间:2023-10-16

我在 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;
}

当 progranm 正在等待 getchar() 时,我正在观察程序的堆大小。而且,这是通过pmap -x <PID> | 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释放内存?

地图的内容将被擦除。与磁盘中的文件类似(仅从索引中删除)。如果下次可以使用它,释放内部存储器将是无效的。

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

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

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

但是,我的堆计数并不反映这一点。

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

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

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

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

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

在C++中没有标准的方法可以做到这一点,但 Linux 提供了一个函数malloc_trim,它将尝试将释放的内存从堆的顶部释放到操作系统。

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

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