造成内存堆积的原因大致分为两类:
1、申请的内存未释放,从而导致内存耗尽
2、申请的速度快于释放的速度,最终导致内存堆积

对于第1种情形,可以运用内存检测工具,相对好解决。常用的工具有valgrind、dmalloc、mtrace、memwatch等工具("https://elinux.org/Memory_Debuggers"有介绍),这些工具对C程序支持比较好,对C++程序,除了valgrind,其他工具支持都不是很好。比如dmalloc对C++的嵌套内存申请不支持,遇到这种情况会直接报错退出。除了上述工具,IBM也有人通过重载new和delete来检测内存泄漏问题,原理很好,但是异常情景还是未考虑到位,还是有一些问题。所以要使用工具,还是使用valgrind,很好的支持C和C++。

对于第2种情形,以下因素会引起内存堆积:
(1)申请线程不断申请,释放线程由于存在睡眠(调用sleep相关函数),被执行时间低于申请线程
(2)由于设置了线程优先级,释放线程优先级偏低申请线程,被执行的频率低于申请线程
(3)在向第三方发送数据的情形(比如socket通信),释放线程发送数据出错时,一直连续发送,而不丢弃数据包和释放内存
(4)还是(3)的情形,释放线程发送数据耗时长,导致释放内存速度慢
(5)接收线程没有对接收的数据包数量做限制,导致内存增长过快

第2种情形出现的内存泄漏问题,目前未找到好的工具可用定位分析,比较不好解决。除了排查代码来查问题,如果申请的都是类对象,且类都有虚函数,可以通过程序的map文件来分析。map文件的heap地址段记录了申请的对象,通过打印出这些地址段的内容,可以知道这些地址段存放的是什么类型的对象,从而减少代码分析的范围。

此外,对于内存堆积问题,可以通过逐个模块排查,比如有A, B, C和D模块,可以先排查A模块,再依次排查其他模块。模块内也可以继续使用这种类似的方法排查。

内存问题最好不要发生,可以使用以下方法预防:
(1)本函数申请的内存尽量在本函数释放
(2)释放内存后,指针置空
(3)new/delete与free/malloc不要混用
(4)使用boost smart_ptr库
(5)在类设计时预留虚函数,用作调试