在C/C++编程中内存泄漏是一个非常普遍和令人头痛的问题,这一问题在嵌入式系统中更为突出。那么如何采用一种好的方法来防范和检测内存泄漏呢?常用的做法有以下几种。
1)采用代码审查的方式进行控制。这种方法是最容易想到的,但是效果也是相当的有限的。当程序复杂度增加的时候,这种方法就越加显得无能为力了。
2)采用一定的工具来帮助发现内存泄漏。比如来自IBM的Purify、开源的Valgrind,等等。这些工具在使用时都不需要我们去改变程序源代码,其使用大至也可以分为两类。第一类是需要对代码进行重新编译,这种方法通常使用起来相对的麻烦,为了方便使用,通常需要将工具与项目的编译环境进行整合。上面所提及的Purify就是采用这类方法的。另一类则不需要对代码进行重新编译,因此,使用起来相当的方便,上面所说到的开源项目Valgrind就是属于这一类的。使用这些工具用于检测内存泄漏时,我们应当注意两点。第一,我们要保证我们的代码在测试时有尽可能高的代码覆盖率。这是因为,内存泄漏的检测需要代码被执行到了,检测工具才能发现。现实情况是,我们往往很难做到百分之百的代码覆盖率,因此检测的效果也是有限的。第二,由于这些工具对于被测程序(代码)的性能有及大的影响,因此,如果内存泄漏检测工具的使用造成程序无法正常运行,那么这类工具是无法使用的。由于以上两点在测试时很有可能造成条件无法满足,因此,不能成为内存泄漏检测的终级解决方法。
3)采用一定的封装技术对内存的分配与释放进行接管。通常提供一个模块或是库对malloc ()、free ()、new、delete和delete []进行很薄的一层封装,然后向应用程序提供相应的API用于分配和释放内存。此外,这个封装层还提供一定的方式让我们能实时的得到运行时内存的使用情况。比如,我们可以看一看刚过去的30分钟内有哪些模块分配了内存且还没有释放,这种方式对于我们现实产品很有意义。比如,对于通讯产品,其可靠性要求通常都很高,我们需要在不终止提供服务的情况下得知当前系统是否有内存泄漏。还有,这种方法由于内存管理模块是作为最终软件产品的一部分的,因此,我们可以随时得知内存的使用情况,这与前面提到的第二种方法是完全不一样的。
对于上面三种情况,从解决方案来看第三种方案最好,但其也存在一些值得我们关注的问题。其一,由于内存管理模块对于每一次内存分配需要记录在哪个文件以及文件的哪一行以用于在需要时显示这些信息。因此,存在一定的内存开销。其二,由于增加了一层的封装,尽管很薄,但内存的分配速度还是会有一点点下降,下降的程序取决于管理算法。从以上两点来看,第三种方法是通过时间和空间来换取实用性的,还是那句话“没有免费的午餐”。
对于不少的产品,由于内存容量不是一个问题、以及CPU的处理速度也足够的快,因此,方法三应当是首选。前面两种方法,在使用上过度的依赖于人或工具,所以很不方便,且对于产品的运行时内存泄漏检测存在一定的局限性。当然,对于第三种方法的可操作性还存在一个问题,比如,程序员并没有采用封装后的API,而是仍然不小心调用了C/C++库的malloc ()和new,那么对于这些内存分配操作,其扰过了我们的内存管理模块。对于这一问题,解决方法就是通过代码审查或是采用搜索工具(很多代码编辑工具都提供搜索功能)进行搜索,看看malloc ()和new是否被调用了,以防止这类事情的发生。
值得一提的是,前面方法二中提到的工具,通常除了内存泄漏的检测外,还可以对很多其它的内存使用问题进行检测,比如,使用没有初始化的指针、内存上溢和下溢出,等等。而这些功能在方法三中是做不到的或者说即使做到了运行时开销也很大,因此,在现实中我们通常会将方法二和方法三结合使用。显然,每种方法所针对的问题是不同的。
本文出自 “李云” 博客,请务必保留此出处http://yunli.blog.51cto.com/831344/170181
阅读(1414) | 评论(0) | 转发(0) |