如何释放 unordered_map 内存?

Dan*_*ina 5 c++ memory memory-leaks memory-management

问题

我已经看到使用map.clear()并且map.rehash(0)不会从我的 RAM 中释放预期的内存。

我用以下代码创建了一个程序:

int main() {
    std::unordered_map<std::string, int> m1;
    std::unordered_map<std::string, int> m2;
    
    // fill the maps m1 and m2 with 5 million elements

    // bucket_count = 5098259; size = 5000000
    
    // now I clear m1
    m1.clear();
    m1.rehash(0);
      // m1: bucket_count = 2; size = 0
      // m2: bucket_count = 5098259; size = 5000000

    // now I clear m2
    m2.clear();
    m2.rehash(1);
      // m1: bucket_count = 2; size = 0
      // m2: bucket_count = 2; size = 0
}
Run Code Online (Sandbox Code Playgroud)

根据程序的每一步bucket_countsize之后,似乎有很多空间从RAM中释放出来。但是,检查与系统监视器一起使用的 RAM,我得到以下演变公羊进化

即使在清除并重新散列两个映射之后,内存也仅在程序完成时释放。实际上释放的内存很少,但我不确定这是否可以在图片中看到。这怎么可能?

我如何才能真正从 RAM 中释放该内存?

语境

我正在使用动态编程算法来解决 Linux 中 4Gb RAM 的旅行商问题。由于内存不足而崩溃,因此我正在尝试优化程序使用的内存。

经过一些改进后,我保留了两个unordered_map

  • cost : 存储上一次迭代的值
  • new_costs:在该迭代期间构建。

迭代结束后,我交换它们,以便cost具有新的计算值,并清除new_costs 以 尝试释放内存并开始构建下一次迭代。

代码是这样的:

std::unordered_map<std::string, int> costs(5098259);
std::unordered_map<std::string, int> new_costs(5098259);

for (int m = 1; m <= n; m++) {
  new_costs.clear();
  new_costs.rehash(5098259);

  while (something) {
    // I build the content of new_costs based on the content of costs
  }

  std::swap(costs, new_costs);
}
Run Code Online (Sandbox Code Playgroud)

我最多必须分别在其中存储 2496144 和 2704156 个元素。这使得总共同时存储了5200300 个元素。鉴于密钥是一个最多包含 70 个字符的字符串 --71 个字节 -- 并且存储的值是一个浮点数 --4 个字节--,我将存储大约 380 Mb。

我知道这unordered_map不是内存有效的,但是程序完全使用了我的 RAM 和我的交换内存,所以我一定遗漏了一些东西。


**编辑可能的重复

如何强制我的 std::map 释放使用的内存?

我已经使用C ++为一个星期左右了,我不知道是不是内存管理std::mapstd::unordered_map是相同的,或者如果它们之间存在着相关差异。

我也不知道解除分配是否与释放对象使用的内存完全相同,因此有更多可用的 RAM。

如果两者相同,我基本上是在问同样的问题。但是,无论如何,该问题的答案是解释内存保留背后的原因,而不是提供解决方案。

Use*_*ess 5

您需要担心三个级别的内存使用情况,并且您的进程内存占用可能向您显示了错误的级别。

  1. 正在使用的内存

    容器中正在使用的东西。简单的。

  2. 每个容器分配器

    您的容器有一个分配器。这可能决定分配比请求更大的块,并且还可能保留释放的内存以供以后重用。这两种方法通常都会以内存使用为代价来提高速度。

    您可以使用交换技巧来释放此缓存:创建一个空的临时容器和std::swap它们。这也会移动分配器,这意味着当临时超出范围时,任何旧的缓存存储都将被释放。

    无论如何,对于释放的某些值:内存可能会返回到您的...

  3. 进程范围的动态分配器(通常是“堆”)。

    出于完全相同的原因,这可能会决定将内存缓存在您的进程中。它没有义务将该内存返回给系统(直到您的进程退出)。

强制程序将内存返回给系统的唯一方法是编写自己的分配器,使用适当的系统调用来显式执行此操作。

在具有虚拟内存的系统上,推断程序内存使用情况的明智方法是担心使用了多少内存,而不是过多担心其虚拟地址空间的大小。

注意。如果尽管您清除并重新使用容器,内存使用量仍持续增长,则可能存在泄漏或内存碎片。这确实是个问题。如果运行期间内存使用量没有减少,则完全正常,无需担心。