最近遇到一个特别占内存的需求。使用STL map/unordered_map,内存无法得到正确释放。再次响应请求,会出现内存溢出的情况。
[6453149.107435] Memory cgroup out of memory: Kill process 54949 (******) score 1001 or sacrifice child
[6453149.117193] Killed process 54779 (******) total-vm:106091668kB, anon-rss:104842716kB, file-rss:1088kB
传统的STL内存释放方法
我们知道,STL容器调用clear()方法,通常只是使得容器内部的对象通通析构,但容器本身的内存无法得到释放。即篮子里面东西拿走了,篮子占的空间还在,这样是为了方便下次存放新的对象时,不需要再次申请空间。
其他同学的blog中有很多例子,即clear()后,容器的size为0,但capacity不变,
-
通过swap()空容器,来彻底释放容器占用的capacity.
vector vec(10000,-1);
vector().swap(vec);
但是这种方法只对vector, string这两个容器有效,这里有大牛的解释;
对于map,set,unordered_map等容器,调用clear(), swap()都无法使得内存真正释放。虽然很多地方谈到,这一现象(内存被保留下来)是正常的,并不需要担心。但是当大量使用堆内存存放不同的数据结构,会造成严重的内存碎片从而导致内存泄漏问题。
实验现象
#include <iostream>
#include <map>
using namespace std;
void func()
{
map<string,string> mp;
int i = 5000000;
while(i--)
mp.insert(make_pair(to_string(i),string("hell000o")));
map<string,string>().swap(mp);
}
int main()
{
func();
cout <<"done."<<endl;
while(1);
}
持续使用top观察内存,发现内存一直持续为最后的峰值。
解决方法
只需添加一行,malloc_trim(0); 这一行代码会将空闲的堆内存归还给操作系统,供其他进程使用。
#include <iostream>
#include <map>
#include <malloc.h>
using namespace std;
void func()
{
map<string,string> mp;
int i = 5000000;
while(i--)
mp.insert(make_pair(to_string(i),string("hell000o")));
map<string,string>().swap(mp);
}
int main()
{
func();
cout <<"done."<<endl;
malloc_trim(0);
while(1);
}