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

15

我正在使用std::map,但似乎无法将内存释放回操作系统。看起来是这样的:

int main(){
  aMap m;

  while(keepGoing){
    while(fillUpMap){
       //populate m
    }
    doWhatIwantWithMap(m);
    m.clear();//doesnt free memory back to OS

    //flush some buffered values into map for next iteration
    flushIntoMap(m);
  }
}
每次(fillUpmap)分配大约1GB的内存,因此我非常希望在它耗尽所有内存之前将其返回到我的系统中。我也遇到了std::vector的同样情况,但是我可以通过与空的std::vector进行交换来强制释放它。但这在map中不起作用。当我使用valgrind时,它显示所有内存都已被释放,因此这不是泄漏的问题,因为运行后所有内容都已清除干净。编辑:清除后必须出现flush。

1
请注意,当您尝试分配内存时,您的操作系统可能会分配地址空间,但只有在您访问该内存时才会分配真正的物理RAM。如果您不再使用该RAM,但其他程序需要它,则其内容将被交换到磁盘上。因此,释放内存实际上是释放RAM。 - MSalters
7个回答

17

m.clear() 会将内存释放回堆,但通常堆的实现不会将其释放回操作系统(即使它们可以,如碎片等问题也很难解决)。

如果您为 map 指定了自己的分配器,则默认分配器的工作方式可能会发生改变,它可能具有自己的缓存。但是,即使在这种情况下,它也应该被缓存以便立即重复使用。

与 vector 不同,map 没有容量和大小的概念。


3

这种行为是正常的,运行时库使映射类分配的内存保持可用状态,以便下一次需要分配内存时不必去操作系统中获取。这是一个运行时库的优化。


2
如果您在堆上创建地图(通过new),则删除它将释放其使用的任何内存。

1

我进行了一个简单的测试,当我将一些数据放入std::map中并调用std::map::clear()时。

typedef std::map<int, unit_t,std::less<int>,  
     my_allocator<std::pair<const int, unit_t>, 4 > > contaner_t;
contaner_t keys;
keys[1] = 10;
keys[2] = 20;
keys[3] = 30;
keys.clear();

这是我测试中插入printf的结果:

Allocator # 4, Memory consumption:      56     (allocated   :       56)
Allocator # 4, Memory consumption:     112     (allocated   :       56)
Allocator # 4, Memory consumption:     168     (allocated   :       56)
Allocator # 4, Memory consumption:     112     (deallocated :       56),
Allocator # 4, Memory consumption:      56     (deallocated :       56),
Allocator # 4, Memory consumption:       0     (deallocated :       56),

我认为你可能也应该检查一下你的分配器行为,但我认为你的默认std::allocator实际上会像你期望的那样释放内存,但是这些内存不会返回给操作系统。顺便问一下,你用的是什么操作系统?

问题在于你如何衡量“似乎无法将内存释放回操作系统”,以及你如何确定“我可以通过与空的std::vector交换来强制释放它”。你真的确定分配的内存实际上会返回到操作系统吗?


1

或许你可以创建一个自定义的分配器,或者直接使用Boost的池库。


1

我猜你在使用Linux。

如果你真的需要最小化应用程序的内存占用,可以在清除映射后调用malloc_trim()。我还建议看一下mallopt()手册——它提供了一些关于为什么你的代码可能会保留内存而不是将其返回给操作系统的提示。


0

《The Linux Programming Interface》的第7.1.2节清晰地解释了有关内存释放的内容:

In general, free() doesn’t lower the program break, but instead adds the block of
memory to a list of free blocks that are recycled by future calls to malloc(). This is
done for several reasons:
- The block of memory being freed is typically somewhere in the middle of the
heap, rather than at the end, so that lowering the program break is not possible.
- It minimizes the number of sbrk() calls that the program must perform. (As
noted in Section 3.1, system calls have a small but significant overhead.)
- In many cases, lowering the break would not help programs that allocate large
amounts of memory, since they typically tend to hold on to allocated memory
or repeatedly release and reallocate memory, rather than release it all and then
continue to run for an extended period of time.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接