Linux C内存泄露检测工具

在Linux下些C语言程序,最大的问题就是没有一个好的编程IDE,当然想kdevelop等工具都相当的强大,但我还是习惯使用kdevelop工具,由于没有一个习惯的编程IDE,内存检测也就成了在Linux下编写程序的一个大问题。

  是不是说没有一种内存检查工具能够在Linux使用呢,也不是,像valgrind工具还是相当不错的。他的下载地址是http://valgrind.org/downloads/current.html#current 下载一个valgrind 3.2.3 (tar.bz2)工具,按照里面的README提示,安装后就可以使用这个工具来检测内存泄露和内存越界等。这是一个没有界面的内存检测工具,安装后,输入valgrind ls -l 验证一下该工具是否工作正常(这是README里面的方法,实际上是验证一下对ls-l命令的内存检测),如果你看到一堆的信息说明你的工具可以使用了。

  在编译你的程序时,请设置-g参数,编译出后使用如下的命令来判断你的程序存在内存泄露:

  valgrind --tools=memcheck --leak-check=fullyourProg在输出信息中就会看到你的内存问题了。关于这些参数是什么意思可以参考valgrind --help的输出信息。


Linux C 编程内存泄露检测工具(一):mtrace
前言

所有使用动态内存分配(dynamic memory allocation)的程序都有机会遇上内存泄露(memoryleakage)问题,在Linux里有三种常用工具来检测内存泄露的情況,包括:

 
  1. mtrace
    2. dmalloc
    3. memwatch

1. mtrace

mtrace是三款工具之中是最简单易用的,mtrace是一个C函數,在<mcheck.h>里声明及定义,函数原型为:
      voidmtrace(void);

其实mtrace是类似malloc_hook的 malloc handler,只不过mtrace的handlerfunction已由系统为你写好,但既然如此,系统又怎么知道你想将malloc/free的记录写在哪里呢?为此,调用mtrace()前要先设置MALLOC_TRACE环境变量:
      #include<stdlib.h>
      ....
      setenv("MALLOC_TRACE", "output_file_name", 1);
      ...

「output_file_name」就是储存检测结果的文件的名称。

但是检测结果的格式是一般人无法理解的,而只要有安装mtrace的话,就会有一名为mtrace的Perlscript,在shell输入以下指令:
      mtrace[binary] output_file_name

就会将output_file_name的內容转化成能被理解的语句,例如「No memory leaks」,「0x12345678Free 10 was never alloc」诸如此类。

例如以下有一函数:(暂且放下single entry single exit的原则)
      #include<stdio.h>
      #include<stdlib.h>
      #include<errno.h>
      #include<mcheck.h>
      int main(){
              char *hello;
   
              setenv("MALLOC_TRACE", "output", 1);
              mtrace();
              if ((hello = (char *) malloc(sizeof(char))) == NULL) {
                      perror("Cannot allocate memory.");
                      return -1;
              }

              return 0;
      }

执行后,再用mtrace 将结果输出:
      - 0x08049670Free 3 was never alloc'd 0x42029acc
      - 0x080496f0Free 4 was never alloc'd 0x420dc9e9
      - 0x08049708Free 5 was never alloc'd 0x420dc9f1
      - 0x08049628Free 6 was never alloc'd 0x42113a22
      - 0x08049640Free 7 was never alloc'd 0x42113a52
      - 0x08049658Free 8 was never alloc'd 0x42113a96

      Memory notfreed:
      -----------------
            Address        Size        Caller
      0x08049a90          0x1  at 0x80483fe

最后一行标明有一个大小为1 byte的内存尚未释放,大概是指「hello」吧。
      若我们把该段内存释放:
      #include<stdio.h>
      #include<stdlib.h>
      #include<errno.h>
      #include<mcheck.h>
      int main(){
              char *hello;
   
              setenv("MALLOC_TRACE", "output", 1);
              mtrace();
              if ((hello = (char *) malloc(sizeof(char))) == NULL) {
                      perror("Cannot allocate memory.");
                      return -1;
              }

              free(hello);
              return 0;
      }

结果如下:
      - 0x080496b0Free 4 was never alloc'd 0x42029acc
      - 0x08049730Free 5 was never alloc'd 0x420dc9e9
      - 0x08049748Free 6 was never alloc'd 0x420dc9f1
      - 0x08049668Free 7 was never alloc'd 0x42113a22
      - 0x08049680Free 8 was never alloc'd 0x42113a52
      - 0x08049698Free 9 was never alloc'd 0x42113a96
      No memoryleaks.

mtrace的原理是记录每一对malloc-free的执行,若每一个malloc都有相应的free,则代表没有内存泄露,对于任何非malloc/free情況下所发生的内存泄露问题,mtrace并不能找出来。


Memwatch简介

在三种检测工具当中,设置最简单的算是memwatch,和dmalloc一样,它能检测未释放的内存、同一段内存被释放多次、位址存取错误及不当使用未分配之内存区域。请往http://www.linkdata.se/sourcecode.html下载最新版本的Memwatch。
安装及使用memwatch

很幸运地,memwatch根本是不需要安装的,因为它只是一组C程序代码,只要在你程序中加入memwatch.h,编译时加上-DMEMWATCH-DMW_STDIO及memwatch.c就能使用memwatch,例如:
gcc -DMEMWATCH -DMW_STDIO test.c memwatch.c -o test


memwatch输出結果

memwatch的输出文件名称为memwatch.log,而且在程序执行期间,所有错误提示都会显示在stdout上,如果memwatch未能写入以上文件,它会尝试写入memwatchNN.log,而NN介于01至99之间,若它仍未能写入memwatchNN.log,则会放弃写入文件。

我们引用第一篇(mtrace)中所使用过的有问题的代码:
      #include<stdio.h>
      #include<stdlib.h>
      #include<errno.h>
      #include<memwatch.h>
      int main(){
              char *hello;

              setenv("MALLOC_TRACE", "output", 1);
              mtrace();
              if ((hello = (char *) malloc(sizeof(char))) == NULL) {
                      perror("Cannot allocate memory.");
                      return -1;
              }

              return 0;
      }

然后在shell中输入以下编译指令:
      gcc-DMEMWATCH -DMW_STDIO test.c memwatch.c -o test

memwatch.log的內容如下:
      ============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh=============

      Started atSat Jun 26 22:48:47 2004

      Modes:__STDC__ 32-bit mwDWORD==(unsigned long)
      mwROUNDALLOC==4 sizeof(mwData)==32 mwDataSize==32


      Stopped atSat Jun 26 22:48:47 2004

              unfreed: <1> test.c(9), 1 bytes at0x805108c      {FE.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .}

      Memory usagestatistics (global):
        N)umber of allocations made: 1
        L)argest memoryusage          : 1
        T)otal of all alloc() calls: 1
        U)nfreed bytestotals          : 1

文件指出,在test.c被执行到第9行时所分配的内存仍未被释放,该段内存的大小为1 byte。
Memwatch使用注意

Memwatch的优点是无需特別配置,不需安装便能使用,但缺点是它会拖慢程序的运行速度,尤其是释放内存时它会作大量检查。但它比mtrace和dmalloc多了一项功能,就是能模拟系统内存不足的情況,使用者只需用mwLimit(longnum_of_byte)函数来限制程式的heap memory大小(以byte单位)。

你可能感兴趣的:(C++)