"內存碎片"疑似“内存泄漏”

来源:互联网 发布:喵社交软件 编辑:程序博客网 时间:2024/05/03 23:55

glibc STL 造成的疑似“内存泄漏”

转载2015-03-26 18:22:49
标签:内存泄漏glibcstltcmallocjemalloc

我维护的一组服务器程序出现了严重的内存泄漏,32GB的内存,几天就跑满了。 

最近几天努力了一下,终于找到原因所在,并解决了问题。

我的程序根据我的计算,内存使用只需要30MB左右。但是观察发现,程序的内存不断上涨。

刚开始就认为发生了,内存泄漏。

于是乎valgrind登场,但是检测了一遍发现,代码层面没有内存泄漏的东西。

但是内存上涨确是不争的事实。为此我怀疑valgrind可能不够准确(现在想想,这个怀疑是错误的)。于是乎,我就开始查看代码,一行一行的读关键代码,还好代码不是很多,要不然就要崩溃了。

​我查看了一下代码中用到new的地方,除了两个map,一个保存session,一个保存数据块,始终存在于进程中外,其他的都是局部变量,会自动释放掉的。

关于session的map, 我初期的工作就是发现被动关闭session的时候,session的信息会从map删掉,主动关闭的session则不会,修复了此BUG,但是内存还是上涨。

数据块的map,我仔细看了代码实在是看不出有什么问题,超过x分钟的数据块会被删掉,当数据块的总大小超过设置的数据缓冲区时,也会删除早期的数据块。

map的元素都按时按规则删除了,怎么内存还是上涨的。

我一直都无法确定到底问题出在哪儿了。


我现在也忘记我当初是怎么找到原因的了。

心里就觉得maperase掉的元素,可能没有及时delete掉(元素是智能指针,计数器什么的)​

在浑浑噩噩查找内存泄漏一天之后,我坐上了回去公交车。

我就拿手机搜了map,内存泄漏。

就那么神奇的出现了,map和glibc被联系到了一起。

我使劲打开博文,​发现glibc的内存分配回收机制的确会导致疑似内存泄漏的现象。

glibc的malloc分配的内存在free之后,并不一定会交还给操作系统,释放的内存会被glibc管理维护,方便下次malloc的时候继续使用。是有满足一定的条件的情况下,释放的内存才会交还给操作系统。在不断的malloc,free之后,某一进程会导致大量的内存碎片产生,这些内存碎片由于glibc的回收机制,很难被交还给操作系统。因而出现“内存泄漏”现象。我的程序也是符合此规律的,内存是缓慢上涨的,但是我的程序实例多,所以内存的消耗的速度还是挺快的。

既然glibc不行,那么有没有其他的内存申请释放库呢? 

答案是有,而且是肯定的。

我当时就搜到了 tcmalloc(google), jemalloc(facebook).

好吧,我是搜到的,我之前是不知道的。

看了一下网上的介绍,这两个的出现的主要目的是解决glibc的分配内存低效的问题(多线程环境下)。

我当时就想了,要是用tcmalloc或者jemalloc能不能解决这个内存碎片的问题呢。

实验发现,tcmalloc不行(我的实验环境不行,网上有其他人说可以)

jemalloc也不行,虽然内存上涨了速度慢了好多,但是还是会上涨,不能从根本上解决问题。

在使用tcmalloc的过程中,我发现了MallocExtension::instance()->GetHeapGrowthStacks​(string )(google perftool的工具,跟tcmalloc一起安装的)

可以发现进程的增长状态。​

​我的代码:

string str;

MallocExtension::instance()->GetHeapGrowthStacks(&str);

  WriteStringToFile(str,"./heap1");

在一个线程中,定期调用。

然后在命令行:pprof --text ./进程名 heap1

即可解析出内存的增长状况,函数名也可以打印出来哦,哈哈(debug版的进程)

我就是这么做的哈。

然后发现我的内存增长就是数据块的map部分啊。

至此我还以为是内存泄漏了

我就打印数据块的释放日志,erase和delete是一一对应的。唉。

至此我终于确定,我释放了数据块,但是碎片我释放不掉。

看着glibc,  再看看tcmalloc和jemalloc。头大了,怎么办呢。

继续搜,发现glibc有一个malloc_trim函数可以强制将glibc保存的待用内存给释放掉,于是我就自己定期释放了,问题解决。


在解决内存泄漏问题的过程中,我获得如下几点认识:

1不要盲目相信glibc, 它虽然是系统默认的,却不一定就好。glibc和stl搭档可能有问题

​2要多阅读多了解,要是早点知道tcmalloc和jemalloc就会少走很多很弯路了。

3valgrind这个东西,怀疑它是可以的,但不要一直怀疑它,精品就是精品

4googleperftool的工具还是要学习一下的,它也是精品

5glibc还有很多东西可以学习,malloc_trim只是一个,还有其他的反应内存分配状况的函数。我觉得glibc提供malloc_trim就是一个极好的设计。我能说tcmalloc和jemalloc都没有这个函数么?他们太自信了。认为不需要这个功能吧。

6作为linux的程序员,系统,内核了解一下,深入了解一下没有坏处。

7遇到事情要执着啊,解决问题会有很大的收获的。尝试尝试再尝试,累了歇歇继续尝试。​

0 0
原创粉丝点击