linux c 內存泄露檢測工具:valgrind

jopen 10年前發布 | 50K 次閱讀 C/C++開發 Valgrind

Linux c/c++上常用內存泄露檢測工具有valgrind, Rational  purifyValgrind免費。Valgrind 可以在 32 位或 64 PowerPC/Linux 內核上工作。
Valgrind
工具包包含多個工具,如Memcheck,Cachegrind,Helgrind,  CallgrindMassif。下面分別介紹個工具的作用:
Memcheck  
工具主要檢查下面的程序錯誤:
? 使用未初始化的內存 (Use of uninitialised  memory)
? 使用已經釋放了的內存 (Reading/writing memory  after it has been freed)
? 使用超過 malloc分配的內存空間(Reading/writing off the  end of mallocd blocks)
? 對堆棧的非法訪問 (Reading/writing  inappropriate areas on the stack)
? 申請的空間是否有釋放 (Memory leaks where pointers to  mallocd blocks are lost  forever)
?  malloc/free/new/delete申請和釋放內存的匹配(Mismatched use of  malloc/new/new [] vs free/delete/delete [])
? srcdst的重疊(Overlapping src and dst  pointers in memcpy() and related functions)
Valgrind
不檢查靜態分配數組的使用情況。
Valgrind
占用了更多的內存--可達兩倍于你程序的正常使用量。如果你用Valgrind來檢測使用大量內存的程序就會遇到問題,它可能會用很長的時間來運行測試
2.1.  
下載安裝
http://www.valgrind.org
安裝
./configure;make;make install
2.2.
編譯程序
被檢測程序加入 g   -fno-inline  編譯選項保留調試信息。

2.3.  
內存泄露檢測
$ valgrind --tool=memcheck  --log-file=/home/trunk/valgrind_log_all --leak-check=full --error-limit=no  --show-leak-kinds=all /opt/lim/bin/limserver

其中--leak-check=full  指的是完全檢查內存泄漏,--show-reachable=yes是顯示內存泄漏的地點,--trace-children=yes是跟入子進程。當程序正常退出的時候valgrind自然會輸出內存泄漏的信息。

1.內存泄露:

#include <stdio.h>void function()
{    int *p = (int*)malloc(10*sizeof(int));    p[10] = 0;
}int main()
{    function();    return 0;
}

相關日志:

==20220== Memcheck, a memory error detector
==20220== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==20220== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==20220== Command: ./test
==20220== Parent PID: 20160
==20220==
==20220== Invalid write of size 4
==20220==    at 0x80483FF: function (in /mnt/Documents/Training/valgrind/test)
==20220==    by 0x8048411: main (in /mnt/Documents/Training/valgrind/test)
==20220==  Address 0x41be050 is 0 bytes after a block of size 40 alloc'd
==20220==    at 0x4028876: malloc (vg_replace_malloc.c:236)
==20220==    by 0x80483F5: function (in /mnt/Documents/Training/valgrind/test)
==20220==    by 0x8048411: main (in /mnt/Documents/Training/valgrind/test)
==20220==
==20220==
==20220== HEAP SUMMARY:
==20220==     in use at exit: 40 bytes in 1 blocks
==20220==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==20220==
==20220== LEAK SUMMARY:
==20220==    definitely lost: 40 bytes in 1 blocks
==20220==    indirectly lost: 0 bytes in 0 blocks
==20220==      possibly lost: 0 bytes in 0 blocks
==20220==    still reachable: 0 bytes in 0 blocks
==20220==         suppressed: 0 bytes in 0 blocks
==20220== Rerun with --leak-check=full to see details of leaked memory
==20220==
==20220== For counts of detected and suppressed errors, rerun with: -v
==20220== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 6)

2.使用未初始化的內存

#include <stdio.h>int main()
{    int a;    if (a==1)
    {        printf("a==%d\n",a);
    }    return 0;
}

日志分析:

==20345== Memcheck, a memory error detector
==20345== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==20345== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==20345== Command: ./test
==20345==
==20345== Conditional jump or move depends on uninitialised value(s)
==20345==    at 0x80483F2: main (in /mnt/Documents/Training/valgrind/test)

==20345==
==20345==
==20345== HEAP SUMMARY:
==20345==     in use at exit: 0 bytes in 0 blocks
==20345==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==20345==
==20345== All heap blocks were freed -- no leaks are possible
==20345==
==20345== For counts of detected and suppressed errors, rerun with: -v
==20345== Use --track-origins=yes to see where uninitialised values come from
==20345== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 6)

可以使用--track-origins=yes 得到更多的信息

3.內存讀寫越界

#include <stdio.h>int main()
{    int *a = (int*)malloc(5*sizeof(int));    a[5] = 1;    return 0;
}

==20368== Memcheck, a memory error detector
==20368== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==20368== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==20368== Command: ./test
==20368==
==20368== Invalid write of size 4
==20368==    at 0x8048404: main (in /mnt/Documents/Training/valgrind/test)
==20368==  Address 0x41be03c is 0 bytes after a block of size 20 alloc'd
==20368==    at 0x4028876: malloc (vg_replace_malloc.c:236)
==20368==    by 0x80483F8: main (in /mnt/Documents/Training/valgrind/test)

==20368==
==20368==
==20368== HEAP SUMMARY:
==20368==     in use at exit: 20 bytes in 1 blocks
==20368==   total heap usage: 1 allocs, 0 frees, 20 bytes allocated
==20368==
==20368== LEAK SUMMARY:
==20368==    definitely lost: 20 bytes in 1 blocks
==20368==    indirectly lost: 0 bytes in 0 blocks
==20368==      possibly lost: 0 bytes in 0 blocks
==20368==    still reachable: 0 bytes in 0 blocks
==20368==         suppressed: 0 bytes in 0 blocks
==20368== Rerun with --leak-check=full to see details of leaked memory
==20368==
==20368== For counts of detected and suppressed errors, rerun with: -v
==20368== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 6)

4.內存申請釋放管理錯誤

#include <stdio.h>int main()
{    int *a = new int[5];    /*free(a);*/    delete a;    return 0;
}

==20387== Memcheck, a memory error detector
==20387== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==20387== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==20387== Command: ./test
==20387==
==20387== Mismatched free() / delete / delete []
==20387==    at 0x4027919: operator delete(void*) (vg_replace_malloc.c:387)
==20387==    by 0x8048498: main (in /mnt/Documents/Training/valgrind/test)
==20387==  Address 0x42f2028 is 0 bytes inside a block of size 20 alloc'd
==20387==    at 0x4027F65: operator new[](unsigned int) (vg_replace_malloc.c:299)
==20387==    by 0x8048488: main (in /mnt/Documents/Training/valgrind/test)

==20387==
==20387==
==20387== HEAP SUMMARY:
==20387==     in use at exit: 0 bytes in 0 blocks
==20387==   total heap usage: 1 allocs, 1 frees, 20 bytes allocated
==20387==
==20387== All heap blocks were freed -- no leaks are possible
==20387==
==20387== For counts of detected and suppressed errors, rerun with: -v
==20387== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 17 from 6)

內存泄露

問題描述:

內存泄露(Memory leak)指的是,在程序中動態申請的內存,在使用完后既沒有釋放,又無法被程序的其他部分訪問。內存泄露是在開發大型程序中最令人頭疼的問題,以至于有 人說,內存泄露是無法避免的。其實不然,防止內存泄露要從良好的編程習慣做起,另外重要的一點就是要加強單元測試(Unit Test),而memcheck就是這樣一款優秀的工具。

下面是一個比較典型的內存泄露案例。main函數調用了mk函數生成樹結點,可是在調用完成之后,卻沒有相應的函數:nodefr釋放內存,這樣內存中的這個樹結構就無法被其他部分訪問,造成了內存泄露。

在一個單獨的函數中,每個人的內存泄露意識都是比較強的。但很多情況下,我們都會對malloc/free 或new/delete做一些包裝,以符合我們特定的需要,無法做到在一個函數中既使用又釋放。這個例子也說明了內存泄露最容易發生的地方:即兩個部分的 接口部分,一個函數申請內存,一個函數釋放內存。并且這些函數由不同的人開發、使用,這樣造成內存泄露的可能性就比較大了。這需要養成良好的單元測試習 慣,將內存泄露消滅在初始階段。

清單 11

linux c 內存泄露檢測工具:valgrind

清單 11.2

linux c 內存泄露檢測工具:valgrind

清單 11.3

linux c 內存泄露檢測工具:valgrind

結果分析:

假設上述文件名位tree.h, tree.cpp, badleak.cpp,生成的可執行程序為badleak,用memcheck對其進行測試,輸出如下。

清單 12

linux c 內存泄露檢測工具:valgrind

該示例程序是生成一棵樹的過程,每個樹節點的大小為12(考慮內存對齊),共8個節點。從上述輸出可以看出,所有的內存泄露都被發現。 Memcheck將內存泄露分為兩種,一種是可能的內存泄露(Possibly lost),另外一種是確定的內存泄露(Definitely lost)。Possibly lost 是指仍然存在某個指針能夠訪問某塊內存,但該指針指向的已經不是該內存首地址。Definitely lost 是指已經不能夠訪問這塊內存。而Definitely lost又分為兩種:直接的(direct)和間接的(indirect)。直接和間接的區別就是,直接是沒有任何指針指向該內存,間接是指指向該內存的 指針都位于內存泄露處。在上述的例子中,根節點是directly lost,而其他節點是indirectly lost。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!