Linux C內存泄露檢測工具

http://blog.chinaunix.net/u/17855/showart_373394.html

在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=full yourProg在輸出信息中就會看到你的內存問題了。關於這些參數是什麼意思可以參考valgrind --help 的輸出信息。


Linux C 編程內存泄露檢測工具(一):mtrace
前言

所有使用動態內存分配(dynamic memory allocation)的程序都有機會遇上內存泄露(memory leakage)問題,在Linux裏有三種常用工具來檢測內存泄露的情況,包括:

   1. mtrace
   2. dmalloc
   3. memwatch

1. mtrace

mtrace是三款工具之中是最簡單易用的,mtrace是一個C函數,在<mcheck.h>裏聲明及定義,函數原型爲:
    void mtrace(void);

其實mtrace是類似malloc_hook的 malloc handler,只不過mtrace的handler function已由系統爲你寫好,但既然如此,系統又怎麼知道你想將malloc/free的記錄寫在哪裏呢?爲此,調用mtrace()前要先設置 MALLOC_TRACE環境變量:
    #include <stdlib.h>
    ....
    setenv("MALLOC_TRACE", "output_file_name", 1);
    ...

「output_file_name」就是儲存檢測結果的文件的名稱。

但是檢測結果的格式是一般人無法理解的,而只要有安裝mtrace的話,就會有一名爲mtrace的Perl script,在shell輸入以下指令:
    mtrace [binary] output_file_name

就會將output_file_name的內容轉化成能被理解的語句,例如「No memory leaks」,「0x12345678 Free 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 將結果輸出:
    - 0x08049670 Free 3 was never alloc'd 0x42029acc
    - 0x080496f0 Free 4 was never alloc'd 0x420dc9e9
    - 0x08049708 Free 5 was never alloc'd 0x420dc9f1
    - 0x08049628 Free 6 was never alloc'd 0x42113a22
    - 0x08049640 Free 7 was never alloc'd 0x42113a52
    - 0x08049658 Free 8 was never alloc'd 0x42113a96

    Memory not freed:
    -----------------
       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;
    }

結果如下:
    - 0x080496b0 Free 4 was never alloc'd 0x42029acc
    - 0x08049730 Free 5 was never alloc'd 0x420dc9e9
    - 0x08049748 Free 6 was never alloc'd 0x420dc9f1
    - 0x08049668 Free 7 was never alloc'd 0x42113a22
    - 0x08049680 Free 8 was never alloc'd 0x42113a52
    - 0x08049698 Free 9 was never alloc'd 0x42113a96
    No memory leaks.

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 at Sat Jun 26 22:48:47 2004

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


    Stopped at Sat Jun 26 22:48:47 2004

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

    Memory usage statistics (global):
     N)umber of allocations made: 1
     L)argest memory usage      : 1
     T)otal of all alloc() calls: 1
     U)nfreed bytes totals      : 1

文件指出,在test.c被執行到第9行時所分配的內存仍未被釋放,該段內存的大小爲1 byte。
Memwatch使用注意

Memwatch 的優點是無需特別配置,不需安裝便能使用,但缺點是它會拖慢程序的運行速度,尤其是釋放內存時它會作大量檢查。但它比mtrace和dmalloc多了一項功能,就是能模擬系統內存不足的情況,使用者只需用mwLimit(long num_of_byte)函數來限制程式的heap memory大小(以byte單位)。

最詳細的使用說明(包括優點缺點,運行原理等)已在README中列出,本人強烈建議各位讀者參考該文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章