作者:gfree.wind@gmail.com
马上就要Release了,可是公司内部运行的盒子,却有两个进程出现了比较严重的内存泄露。先检查了Coverity的检测报告——Coverity是一个很不错的静态代码检测工具,只找到了一处真正的内存泄露。因为是公司线上使用的盒子,没有办法使用valgrind去检查,因为valgrind必然会降低性能,那么公司的网络就会出现问题。
唉,没办法,只能人工review代码了。通过pmap查看进程的内存分布,确认了不断增长的内存是堆上的。那么也就是malloc后,没有free。用了两天时间把所有malloc的代码都过了一遍。由于很多地方是嵌套好几层以后,malloc的内存,然后在外层释放的,所有检查起来还是比较困难。我开了几个SourceInsight,最终一共找到了7处严重的内存泄露——有一处与Coverity找到的相同。
大致有3种情况,造成了内存泄露:
1. 调用sqlite的API。其中1个是申请某资源的句柄,另外一个是释放该句柄;造成内存泄露的原因是,连续调用了2次申请资源的API。——以我的猜想,估计是同事认为,第一个API是可以连续使用的,殊不知sqilte中并不会检测输入参数,进入该API后,会直接初始化参数,然后申请资源赋给该参数。也就说第一个资源的句柄完全丢失了;
2. 自己定义的1对API,一个是申请内存,另外一个是释放内存。申请内存是为3个成员变量指针申请了内存,而释放时只释放了2个。——估计是加入新的feature时,只更新了初始化函数,会忘记了释放函数。
3. 遗漏了释放句柄的代码。——纯粹是马虎。
当我花了2天时间去检查内存泄露问题,觉得这个事情仅仅是琐碎而已。如果在编码过程中,养成好的习惯,写了申请内存的代码,立刻就在后面加上释放的代码,就可以避免不少内存泄露。
更好的方法是,如果我们使用C++的话,大部分的内存泄露都可以避免了。资源使用类进行包装,析构时检测释放资源。其实是动态申请,通过使用智能指针来封装,也可以避免内存泄露。
虽然一直都说C++在性能上跟C还是有一些差距的。但是在大部分代码中,仍然可以把C++当成C来写,不使用其他的C++特性。只在内存,锁,文件句柄等资源上,进行类的包装,就可以避免遗漏资源的释放。
可是为什么我们不能这样干呢?
阅读(674) | 评论(0) | 转发(0) |