C/C++內存泄露檢測

如下測試基於的gcc版本:html

gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.linux

1、mtrace
一、介紹
  mtrace是包含在GNU C庫裏一個內存調試工具。mtrace()函數爲內存分配函數(malloc,realloc,free)安裝hook函數,這些hook函數用於記錄內存的分配與釋放的跟蹤信息,這些跟蹤信息可用於發現內存泄露。ubuntu

  muntrace()函數會使已安裝的hook函數失效,因此就再也不對內存的分配進行跟蹤。當mtrace()被調用時,它會檢查環境變量MALLOC_TRACE的值,內存分配信息會記錄下該環境變量所指的文件裏。ide

  一般狀況下,mtrace()程序執行前調用,而muntrace不用調用,由於有些內存要在程序結束時纔會釋放。mtrace所產生的跟蹤信息是文本文件,但不易於人理解,可經過GNU C庫提供的Perl腳原本解釋。爲了可以獲得文件的具體位置出現了內存泄露,程序須要以debug模式編譯。函數

二、使用步驟
  1)main函數所在文件包含頭文件的 <mcheck.h>,main函數開頭調用mtrace()
  2)以debug模式編譯源代碼
  3) 設置環境變量MALLOC_TRACE=output_file指定記錄跟蹤信息的文件路徑(實測代表在代碼裏設置環境變量纔有效)
  4)執行可執行程序 ./test, 會生成output_file文件
  5)執行GNU C提供的Perl的腳本: mtrace test output_file
三、實例工具

  //test.c: 
1 #include <mcheck.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 5 int main(int argc, char *argv[]) 6 { 7 setenv("MALLOC_TRACE","output_file",1); 8 mtrace(); 9 10 for (int j = 0; j < 2; j++) 11 malloc(2); /* Never freed--a memory leak */ 12 13 calloc(2,2); /* Never freed--a memory leak */ 14 exit(EXIT_SUCCESS); 15 }

   執行: gcc -g test.c -o test測試

           ./test this

           mtrace test output_file spa

   檢測結果:開放源代碼

- 0x084f8008 Free 5 was never alloc'd 0xb7617024
- 0x084f8070 Free 6 was never alloc'd 0xb76cb866
- 0x084f8090 Free 7 was never alloc'd 0xb76cb86e

Memory not freed:
-----------------
Address Size Caller
0x084f8418 0x2 at /home/zpy/tmp/test.c:10 (discriminator 2)
0x084f8428 0x2 at /home/zpy/tmp/test.c:10 (discriminator 2)
0x084f8438 0x4 at /home/zpy/tmp/test.c:14

     內存泄露的大小及位置都顯示出來了。

四、總結:

  mtrace僅僅能檢測C語言中經過malloc、realloc等分配的內存,並不能對C++中經過new分配的內存,須要對源代碼從新編譯才能檢測。

 

2、memwatch 

 一、介紹

memwatch是一個內存泄露檢測工具,其特徵以下:

    • 支持ANSI C
    • 檢測屢次釋放內存,以及錯誤的釋放方式
    • 檢測未釋放的內存
    • 檢測內存buffer的上溢與下溢
    • 檢測對野指針的寫
    • 部分支持C++(默認disabled)

二、使用方式:

  1)下載memwatch包,解壓

  2)在全部須要進行檢測的代碼源文件中都包含 memwath.h 頭文件

    3)從新編譯源代碼,並指定宏定義MEMWATCH  MEMWATCH_STDIO

  4)執行程序./test 

  5)查看生成的文件memwatch.log內容

三、實例:

//test.c
1 #include <stdlib.h> 2 #include <stdio.h> 3 #include "memwatch.h" 4 int main(int argc, char *argv[]) 5 { 6 for (int j = 0; j < 2; j++) 7 malloc(2); /* Never freed--a memory leak */ 8 9 calloc(2,2); /* Never freed--a memory leak */ 10 exit(EXIT_SUCCESS); 11 }

  編譯: gcc -DMEMWATCH -DMW_STDIO  test.c memwatch.c -o test

  運行:./test 

  查看memwatch.log文件:

  1                                                                                                                                                                         
  2 ============= MEMWATCH 2.71 Copyright (C) 1992-1999 Johan Lindh =============
  3 
  4 Started at Sat Apr 16 02:54:55 2016
  5 
  6 Modes: __STDC__ 64-bit mwDWORD==(unsigned long)
  7 mwROUNDALLOC==8 sizeof(mwData)==32 mwDataSize==32
  8 
  9 
 10 Stopped at Sat Apr 16 02:54:55 2016
 11 
 12 unfreed: <3> test.c(9), 4 bytes at 0x92a6260      {00 00 00 00 .. .. .. .. .. .. .. .. .. .. .. .. ....}
 13 unfreed: <2> test.c(7), 2 bytes at 0x92a6228      {FE FE .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..}
 14 unfreed: <1> test.c(7), 2 bytes at 0x92a61f0      {FE FE .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..}
 15 
 16 Memory usage statistics (global):
 17  N)umber of allocations made: 3
 18  L)argest memory usage      : 8
 19  T)otal of all alloc() calls: 8
 20  U)nfreed bytes totals      : 8

 四、總結:

  memwatch可以較好地對C語言中的內存泄露進行檢測,對C++ 中new分配的內存不建議採用些工具檢測,由於它對C++支持不完善。使用該工具須要從新編譯源代碼,並須要在全部的源文件中都要包含頭文件 "memwatch.h"

3、LeakTracer

 一、介紹

LeakTracer是一個小型的C++內存泄露檢測工具。它可以檢測以下內存問題:

    • 未釋放的內存
    • 對超出所分配內存範圍外的overwritten
    • 試圖釋放並未分配的內存(好比釋放garbage pointer以及屢次釋放)
    • 釋放與分配函數的不匹配,如使用new[]分配,而使用delete釋放

  在使用LeakTracer時,經過提供的LeakCheck腳本運行你的程序,它使用LD_PRELOAD在你的函數上層進行「重寫」。若是你的平臺不支持LD_PRELOAD,則須要將LeakTracer.o 對象文件加入到Makefile文件中,而後運行你的應用程序

  LeakTracer利用gdb去輸出發生內存泄露所發生的位置,它是經過override operator new和operator delete來實現檢測。

二、使用方法:

  1)下載LeakTracer

  2)解壓,執行make, 會生成LeakTracer.so

  3)以debug模式編譯源代碼

  4)經過提供的LeakCheck運行程序:./LeakCheck ./test ,會生成leak.out文件

  5)經過提供的leak-analyze腳本分析結果:./leak-analyze test leak.out (leak-analyze 會加載LeakTracer.so,因此注意路徑)

三、實例:

  1 // Small leaky test program                                                                                                                                             
  2 
  3 void foo() {
  4     int *x = new int;
  5 }
  6 
  7 int main() {
  8     int *z = new int[10];
  9     char *q = new char[4];
 10     q[4] = 'x';                 // MAGIC overrun
 11     // Commenting out should make this abort
 12     // delete q;
 13     foo();
 14     foo();
 15     delete z;
 16     delete z;   // delete value twice
 17 }

  執行:

  g++ -g test.cc -o test 

  ./LeakCheck ./test

  ./leak-analyze test leak.out

  檢測結果:

Gathered 4 (3 unique) points of data.
Reading symbols from test...done.
(gdb) 
#-- Alloc: Different allocation schemes
alloc here :0x8048569 is in main() (test.cc:8).
7    int main() {
8        int *z = new int[10];
..free here :0x804859d is in main() (test.cc:16).
16        delete z;   // delete value twice

#-- Leak: counted 2x / total Size: 8
0x804854f is in foo() (test.cc:4).
3    void foo() {
4        int *x = new int;

#-- Leak: counted 1x / total Size: 4
0x8048579 is in main() (test.cc:9).
8        int *z = new int[10];
9        char *q = new char[4];

#-- delete on not allocated memory: counted 1x
0x80485a9 is in main() (test.cc:17).
16        delete z;   // delete value twice
17    }

  檢測結果反映出發生內存泄露相關的代碼,以及所在的文件和行號,很是Nice!

四、總結:

  LeakTracer僅可以檢測new/new[] 分配的內存,對於C中malloc等分配的內存沒法檢測。無需對對源代碼進行從新編譯。

4、Varlgrind
一、介紹

  Valgrind是一套Linux下,開放源代碼(GPL V2)的仿真調試工具的集合,其中最經常使用的工具是Memcheck。

Memcheck是一個內存錯誤檢測工具,它可以檢測在C/C++中廣泛存在的問題:

    • 對未初始化內存的使用
    • 讀/寫釋放後的內存
    • 讀/寫超出malloc分配的內存塊
    • 讀/寫不適當的棧中內存塊
    • 內存泄漏,指向一塊內存的指針永遠丟失
    • malloc/new/new[]與free/delete/delete[]等的不匹配
    • memcpy()相關函數中的dst和src指針重疊

二、使用方法

valgrind [valgrind-options] your-prog [your-prog-options]

  valgrind-options又分爲對全部工具都適用的一些公共選項,以及僅對某個工具適用的選項。默認狀況下,--tool=memcheck,也就是說默認使用工具Memcheck。

  執行: valgrind ./your-grog [your-prog-options]  便可對程序進行內存檢測

  1)經常使用的公共選項:(更多詳細選項:http://valgrind.org/docs/manual/manual-core.html#manual-core.options)

--tool=<toolname> [default: memcheck]

運行toolname指定的Valgrind,例如,Memcheck, Addrcheck, Cachegrind,等等。

--log-fd=<number> [default: 2, stderr]

指定Valgrind把它全部的消息都輸出到一個指定的文件描述符中去。

--log-file=<filename>

指定Valgrind把它全部的信息輸出到指定的文件中。

  2)Memcheck經常使用選項:(更多詳細選項:http://valgrind.org/docs/manual/mc-manual.html)

--leak-check=<no|summary|yes|full> [default: summary]

當這個選項打開時,當客戶程序結束時查找內存泄漏。內存泄漏意味着有用malloc分配內存塊,可是沒有用free釋放,並且沒有指針指向這塊內存。這樣的內存塊永遠不能被程序釋放,由於沒有指針指向它們。若是設置爲summary,Valgrind會報告有多少內存泄漏發生了。若是設置爲full或yes,Valgrind給出每個獨立的泄漏的詳細信息。

三、實例:

  1 #include <stdlib.h>                                                                                                                                                     
  2 #include <stdio.h>
  3 
  4 int main(int argc, char *argv[])
  5 {
  6     for (int j = 0; j < 2; j++)
  7         malloc(2);            /* Never freed--a memory leak */
  8 
  9     calloc(2,2);             /* Never freed--a memory leak */
 10     exit(EXIT_SUCCESS);
 11 }

 

   執行:valgrind --leak-check=full ./test 

   檢測結果以下:

==15916== Memcheck, a memory error detector
==15916== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==15916== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==15916== Command: ./test
==15916== 
==15916== 
==15916== HEAP SUMMARY:
==15916==     in use at exit: 8 bytes in 3 blocks
==15916==   total heap usage: 3 allocs, 0 frees, 8 bytes allocated
==15916== 
==15916== 4 bytes in 1 blocks are definitely lost in loss record 1 of 2
==15916==    at 0x402C109: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15916==    by 0x80484BB: main (test.c:9)
==15916== 
==15916== 4 bytes in 2 blocks are definitely lost in loss record 2 of 2
==15916==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==15916==    by 0x804849B: main (test.c:7)
==15916== 
==15916== LEAK SUMMARY:
==15916==    definitely lost: 8 bytes in 3 blocks
==15916==    indirectly lost: 0 bytes in 0 blocks
==15916==      possibly lost: 0 bytes in 0 blocks
==15916==    still reachable: 0 bytes in 0 blocks
==15916==         suppressed: 0 bytes in 0 blocks
==15916== 
==15916== For counts of detected and suppressed errors, rerun with: -v
==15916== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

對於以上幾種內存泄露的解釋:

"definitely lost":確認丟失。程序中存在內存泄露,應儘快修復。當程序結束時若是一塊動態分配的內存沒有被釋放且經過程序內的指針變量均沒法訪問這塊內存則會報這個錯誤。
"indirectly lost":間接丟失。當使用了含有指針成員的類或結構時可能會報這個錯誤。這類錯誤無需直接修復,他們老是與"definitely lost"一塊兒出現,只要修復"definitely lost"便可。
"possibly lost": 發現了一個指向某塊內存中部的指針,而不是指向內存塊頭部。這種指針通常是原先指向內存塊頭部,後來移動到了內存塊的中部,還有可能該指針和該內存根本就沒有關係,檢測工具只是懷疑有內存泄漏
"still reachable": 表示泄漏的內存在程序運行完的時候,仍舊有指針指向它,於是,這種內存在程序運行結束以前能夠釋放。通常狀況下valgrind不會報這種泄漏,除非使用了參數 --show-reachable=yes。

四、總結:

可以較好的C/C++內存分配引發的內存泄露。無需對源代碼進行從新編譯,直接對二進制進行檢測。

 

5、tcmalloc

一、介紹:

  tcmalloc是一個相似於malloc的內存分配庫,但同時提供了內存泄露檢測與內存分析的功能。

二、使用方法

  1) 首先連接libtcmalloc庫,連接有兩種方式:

       a) 從新編譯,加編譯選項 -tcmalloc;

    b) 無需編譯,執行程序前加 LD_PRELOAD=/usr/local/libtcmalloc.so

  2) 找開heap check功能:

    a) 設置環境變量HEAPCHECK=normal/strict/draconian,對整個程序進行檢查

    b) 對部分代碼進行檢查:

      HeapProfileLeakChecker checker("foo");

        Foo();    //待檢查部分

      assert(checker.NoLeaks());

  3) 執行程序後,即後得出檢測結果

相關文章
相關標籤/搜索