Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8104306
  • 博文数量: 159
  • 博客积分: 10424
  • 博客等级: 少将
  • 技术积分: 14615
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-14 12:45
个人简介

啦啦啦~~~

文章分类
文章存档

2015年(5)

2014年(1)

2013年(5)

2012年(10)

2011年(116)

2010年(22)

分类: C/C++

2011-01-21 22:15:22

作者: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++特性。只在内存,锁,文件句柄等资源上,进行类的包装,就可以避免遗漏资源的释放。

可是为什么我们不能这样干呢?
阅读(7857) | 评论(7) | 转发(3) |
给主人留下些什么吧!~~

GFree_Wind2011-04-10 20:24:01

captivated: 严重同意。C几乎没有办法避免资源泄漏。忘记释放甚至“不知道该在什么时候释放”是非常常见的事情。
C++的RAII可以进行真正的资源管理并防止资源泄漏。当然RAII.....
不可能换成C++代码了。毕竟是底层代码,而且代码量太大了

captivated2011-04-10 15:28:00

严重同意。C几乎没有办法避免资源泄漏。忘记释放甚至“不知道该在什么时候释放”是非常常见的事情。
C++的RAII可以进行真正的资源管理并防止资源泄漏。当然RAII严重依赖析构函数的自动调用,但既然计算机能做好的事情就不要人去做了。
不过LZ的那份源码中可能太多C遗留代码了...要全部换成C++吗?...而且如果换成C++的话...