在 Linux / Windows平台中调试 C/C++ 内存泄漏方法

2014-11-24 08:59:33 ? 作者: ? 浏览: 0

1. 如何发现内存泄漏


有些简单的内存泄漏问题可以从在代码的检查阶段确定。还有些泄漏比较严重的,即在很短的时间内导致程序或系统崩溃,或者系统报告没有足够内存,也比较容易发现。最困难的就是泄漏比较缓慢,需要观测几天、几周甚至几个月才能看到明显异常现象。那么如何在比较短的时间内检测出有没有潜在的内存泄漏问题呢?实际上不同的系统都带有内存监视工具,我们可以从监视工具收集一段时间内的堆栈内存信息,观测增长趋势,来确定是否有内存泄漏。在 Linux 平台可以用 ps 命令,来监视内存的使用,比如下面的命令 (观测指定进程的VSZ值):




2. 静态分析


包括手动检测和静态工具分析,这是代价最小的调试方法。


2.1 手动检测


当使用 C/C++ 进行开发时,采用良好的一致的编程规范是防止内存问题第一道也是最重要的措施。检测是编码标准的补充。二者各有裨益,但结合使用效果特别好。专业的 C 或 C++ 专业人员甚至可以浏览不熟悉的源代码,并以极低的成本检测内存问题。通过少量的实践和适当的文本搜索,您能够快速验证平衡的 *alloc() 和 free() 或者 new 和 delete 的源主体。人工查看此类内容通常会出现像清单 1 中一样的问题,可以定位出在函数 LeakTest 中的堆变量 Logmsg 没有释放。


清单1. 简单的内存泄漏



2.2 静态代码分析工具


代码静态扫描和分析的工具比较多,比如 splint, PC-LINT, BEAM 等。因为 BEAM 支持的平台比较多,这以 BEAM 为例,做个简单介绍,其它有类似的处理过程。


BEAM 可以检测四类问题: 没有初始化的变量;废弃的空指针;内存泄漏;冗余计算。而且支持的平台比较多。


BEAM 支持以下平台:



清单2. 用作 Beam 分析的代码



下面以 X86 Linux 为例,代码如清单 2,具体的环境如下:


GCC: gcc version 3.4.4


BEAM: 3.4.2; https://w3.eda.ibm.com/beam/


可以把 BEAM 看作一个 C/C++ 编译器,按下面的命令进行编译 (前面两个命令是设置编译器环境变量):



从下面的编译报告中,我们可以看到这段程序中有三个错误:”内存泄漏”;“变量未初始化”;“ 空指针操作”



3. 动态运行检测


实时检测工具主要有 valgrind, Rational purify 等。


3.1 Valgrind


valgrind 是帮助程序员寻找程序里的 bug 和改进程序性能的工具。程序通过 valgrind 运行时,valgrind 收集各种有用的信息,通过这些信息可以找到程序中潜在的 bug 和性能瓶颈。


Valgrind 现在提供多个工具,其中最重要的是 Memcheck,Cachegrind,Massif 和 Callgrind。Valgrind 是在 Linux 系统下开发应用程序时用于调试内存问题的工具。它尤其擅长发现内存管理的问题,它可以检查程序运行时的内存泄漏问题。其中的 memecheck 工具可以用来寻找 c、c++ 程序中内存管理的错误。可以检查出下列几种内存操作上的错误:


3.2 Rational purify


Rational Purify 主要针对软件开发过程中难于发现的内存错误、运行时错误。在软件开发过程中自动地发现错误,准确地定位错误,提供完备的错误信息,从而减少了调试时间。同时也是市场上唯一支持多种平台的类似工具,并且可以和很多主流开发工具集成。Purify 可以检查应用的每一个模块,甚至可以查出复杂的多线程 或进程应用中的错误。另外不仅可以检查 C/C++,还可以对 Java 或 .NET 中的内存泄漏问题给出报告。


在 Linux 系统中,使用 Purify 需要重新编译程序。通常的做法是修改 Makefile 中的编译器变量。下面是用来编译本文中程序的 Makefile:



首先运行 Purify 安装目录下的 purifyplus_setup.sh 来设置环境变量,然后运行 make 重新编译程序。



下面给出编译一个代码文件的示例,源代码文件命名为 test3.cpp. 用 purify 和 g++ 的编译命令如下,‘-g’是编译时加上调试信息。



运行编译生成的可执行文件 test,就可以得到图1,可以定位出内存泄漏的具体位置。




清单3. Purify 分析的代码


-->

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: