C/C++程序一般都由程序员自己来控制内存的申请和释放,因此稍有不慎就容易出现内存泄漏,大家平时开发中都用什么方法和手段来检测、调试程序的内存泄漏呢?

1. 如何发现内存泄漏

ps -aux

2. 静态分析

**2.1 手动检测**
#include <stdio.h> 
#include <string.h>
#include <stdlib.h>
int LeakTest(char * Para)
{
    if(NULL==Para)
    { 
        //local_log("LeakTest Func: empty parameter\n"); 
        return -1; 
    } 
    char * Logmsg = new char[128]; 
    if(NULL == Logmsg)
    { 
        //
        local_log("memeory allocation failed\n");
        return -2; 
    } 
    sprintf(Logmsg,"LeakTest routine exit: '%s'.\n", Para); 
    local_log(Logmsg); return 0; 
} 
int main(int argc,char **argv )
{ 
    char szInit [] = "testcase1";
    LeakTest(szInit);
    return 0; 
}

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

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

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
int *p; 
void foo(int a)
{ 
    int b, c; b = 0; 
    if(!p) 
        c = 1; 
    if(c > a) 
        c += p[1]; 
} 
int LeakTest(char * Para)
{ 
    char * Logmsg = new char[128];
    if((Para==NULL)||(Logmsg == NULL))
        return -1;
    sprintf(Logmsg,"LeakTest routine exit: '%s'.\n", Para); 
    return 0; 
} 
int main(int argc,char **argv ) 
{
    char szInit [] = "testcase1"; 
    LeakTest(szInit); 
    return 0; 
}

**2.3 内嵌程序**

可以重载内存分配和释放函数 new 和 delete,然后编写程序定期统计内存的分配和释放,从中找出可能的内存泄漏。或者调用系统函数定期监视程序堆的大小,关键要确定堆的增长是泄漏而不是合理的内存使用。这类方法比较复杂,在这就不给出详细例子了。

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 中的内存泄漏问题给出报告。

示例代码

#include <unistd.h>
char * Logmsg; 
int LeakTest(char * Para) 
{ 
    if(NULL==Para)
    { //
        local_log("LeakTest Func: empty parameter\n"); 
        return -1; 
    } 
    Logmsg = new char[128]; 
    for (int i = 0 ; i < 128; i++)
        Logmsg[i] = i%64;
    if(NULL == Logmsg)
    { //
        local_log("memeory allocation failed\n"); 
        return -2; 
    }
    sprintf(Logmsg,"LeakTest routine exit: '%s'.\n", Para);
    //
    local_log(Logmsg); 
    return 0; 
} 
int main(int argc,char **argv ) 
{ 
    char szInit [] = "testcase1";
    int i; 
    LeakTest(szInit);
    for (i=0; i < 2; i++)
    { if(i%200 == 0) 
    LeakTest(szInit); 
    sleep(1); 
    } 
    return 0; 
}
  1. “内存泄露”包括堆内存泄露、栈内存泄露。根据内存的类型,又分为:内存申请、释放,句柄的打开与关闭问题。
  2. 容易忽视的是栈上的内存泄露,严格来讲是申请的内存超过线程栈空间大小(默认为1MB)。栈上的内存(即局部变量)是不需要释放的,函数返回自动出栈(释放)。若某时刻超过线程栈空间大小,造成其它使用栈的地方不能正常工作(如函数调用、SEH等),会使程序崩溃(驱动的话会蓝屏)。所以申请局部变量内存时,不要太大。
  3. 堆内存申请、释放。主要是要注意申请的地方要记得释放,以及申请、释放函数要配对使用。比如malloc和free、new和delete、BSTR的SysAllocString和SysFreeString。
  4. 还有一个地方也往往被忽略,”句柄的打开与关闭问题”。这个当积累到一定数量,是很占内存的。可以linux上的加强进程查看工具观察,若handle数量很大或一直在增长,说明有泄漏。windows下则可以使用微软内核套件SysinternalsSuite出品的procexp.exe工具,如下图:
    请输入图片描述

看到handles栏了吗。

另外,完全可以重载new、delete等方法,实现简单的垃圾回收,很多软件都这么做。这也是<<Effective C++>>上推荐的。

» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

   
© 2012 velep.com | reille blog | 管理| 粤ICP备12094833号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量