調不盡的記憶體洩露,用不完的Valgrind
(一個介紹程式調試的精彩講解:http://www.ibm.com/developerworks/cn/linux/l-pow-debug/ )
Valgrind 介紹
Valgrind 是一個GPL的軟體,用于Linux(For x86, amd64 and ppc32)程式的記憶體調試和代碼剖析。你可以在它的環境中運作你的程式來監視記憶體的使用 情況,比如C 語言中的malloc和free或者 C++中的new和 delete。使用 Valgrind 的工具包,你可以自動的檢測許多記憶體管理和線程的bug,避免花費太多的時間在bug尋找上,使得你的程式更加穩固。
Valgrind 的主要功能
Valgrind 工具包包含多個工具,如Memcheck,Cachegrind,Helgrind, Callgrind,Massif。下面分别介紹個工具的作用:
Memcheck 工具主要檢查下面的程式錯誤:
- 使用 未初始化的記憶體 (Use of uninitialised memory)
- 使用 已經釋放了的記憶體 (Reading/writing memory after it has been free’d)
- 使用 超過 malloc配置設定的記憶體空間(Reading/writing off the end of malloc’d blocks)
- 對堆棧的非法通路 (Reading/writing inappropriate areas on the stack)
- 申請的空間是否有釋放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
- malloc/free/new/delete申請和釋放記憶體的比對(Mismatched use of malloc/new/new [] vs free/delete/delete [])
- src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions)
Callgrind
Callgrind收集程式運作時的一些資料,函數調用關系等資訊,還可以有選擇地進行cache 模拟。在運作結束時,它會把分析資料寫入一個檔案。callgrind_annotate可以把這個檔案的内容轉化成可讀的形式。
Cachegrind
它模拟 CPU中的一級緩存I1,D1和L2二級緩存,能夠精确地指出程式中 cache的丢失和命中。如果需要,它還能夠為我們提供cache丢失次數,記憶體引用次數,以及每行代碼,每個函數,每個子產品,整個程式産生的指令數。這對優化程式有很大的幫助。
Helgrind
它主要用來檢查多線程程式中出現的競争問題。Helgrind 尋找記憶體中被多個線程通路,而又沒有一貫加鎖的區域,這些區域往往是線程之間失去同步的地方,而且會導緻難以發掘的錯誤。Helgrind實作了名為” Eraser” 的競争檢測算法,并做了進一步改進,減少了報告錯誤的次數。
Massif
堆棧分析器,它能測量程式在堆棧中使用 了多少記憶體,告訴我們堆塊,堆管理塊和棧的大小。Massif能幫助我們減少記憶體的使用 ,在帶有虛拟記憶體的現代系統中,它還能夠加速我們程式的運作,減少程式停留在交換區中的幾率。
Valgrind 安裝
1、 到www.valgrind
.org下載下傳最新版valgrind
-3.2.3.tar.bz2
2、 解壓安裝包:tar –jxvf valgrind
-3.2.3.tar.bz2
3、 解壓後生成目錄valgrind
-3.2.3
4、 cd valgrind
-3.2.3
5、 ./configure
6、 Make;make install
Valgrind 使用
用法: valgrind [options] prog-and-args [options]: 常用選項,适用于所有Valgrind 工具
- -tool=<name> 最常用的選項。運作 valgrind 中名為toolname的工具。預設memcheck。
- h –help 顯示幫助資訊。
- -version 顯示 valgrind 核心的版本,每個工具都有各自的版本。
- q –quiet 安靜地運作,隻列印錯誤資訊。
- v –verbose 更詳細的資訊, 增加錯誤數統計。
- -trace-children=no|yes 跟蹤子線程? [no]
- -track-fds=no|yes 跟蹤打開的檔案描述?[no]
- -time-stamp=no|yes 增加時間戳到LOG資訊? [no]
- -log-fd=<number> 輸出LOG到描述符檔案 [2=stderr]
- -log-file=<file> 将輸出的資訊寫入到filename.PID的檔案裡,PID是運作程式的進行ID
- -log-file-exactly=<file> 輸出LOG資訊到 file
- -log-file-qualifier=<VAR> 取得環境變量的值來做為輸出資訊的檔案名。 [none]
- -log-socket=ipaddr:port 輸出LOG到socket ,ipaddr:port
LOG資訊輸出
- -xml=yes 将資訊以xml格式輸出,隻有memcheck可用
- -num-callers=<number> show <number> callers in stack traces [12]
- -error-limit=no|yes 如果太多錯誤,則停止顯示新錯誤? [yes]
- -error-exitcode=<number> 如果發現錯誤則傳回錯誤代碼 [0=disable]
- -db-attach=no|yes 當出現錯誤, valgrind 會自動啟動調試器gdb。[no]
- -db-command=<command> 啟動調試器的指令行選項[gdb -nw %f %p]
适用于Memcheck工具的相關選項:
- -leak-check=no|summary|full 要求對leak給出詳細資訊? [summary]
- -leak-resolution=low|med|high how much bt merging in leak check [low]
- -show-reachable=no|yes show reachable blocks in leak check? [no]
Valgrind 使用 舉例
下面是一段有問題的C程式代碼test.c
#include <stdlib.h>
void f(void)
{
int* x = malloc(10 * sizeof(int));
x[10] = 0; //問題1: 數組下标越界
} //問題2: 記憶體沒有釋放
int main(void)
{
f();
return 0;
}
1、 編譯程式test.c
gcc -Wall test.c -g -o test
2、 使用
Valgrind
檢查程式BUG
valgrind
--tool=memcheck --leak-check=full ./test
3、 分析輸出的調試資訊
==3908== Memcheck, a memory error detector.
==3908== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==3908== Using LibVEX rev 1732, a library for dynamic binary translation.
==3908== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==3908== Using valgrind
-3.2.3, a dynamic binary instrumentation framework.
==3908== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==3908== For more details, rerun with: -v
==3908==
--3908-- DWARF2 CFI reader: unhandled CFI instruction 0:50
--3908-- DWARF2 CFI reader: unhandled CFI instruction 0:50
/*數組越界錯誤*/
==3908== Invalid write of size 4
==3908== at 0x8048384: f (test.c:6)
==3908== by 0x80483AC: main (test.c:11)
==3908== Address 0x400C050 is 0 bytes after a block of size 40 alloc'd
==3908== at 0x40046F2: malloc (vg_replace_malloc.c:149)
==3908== by 0x8048377: f (test.c:5)
==3908== by 0x80483AC: main (test.c:11)
==3908==
==3908== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 1)
==3908== malloc/free: in use at exit: 40 bytes in 1 blocks.
==3908== malloc/free: 1 allocs, 0 frees, 40 bytes allocated.
==3908== For counts of detected errors, rerun with: -v
==3908== searching for pointers to 1 not-freed blocks.
==3908== checked 59,124 bytes.
==3908==
==3908==
/*有記憶體空間沒有釋放*/
==3908== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3908== at 0x40046F2: malloc (vg_replace_malloc.c:149)
==3908== by 0x8048377: f (test.c:5)
==3908== by 0x80483AC: main (test.c:11)
==3908==
==3908== LEAK SUMMARY:
==3908== definitely lost: 40 bytes in 1 blocks.
==3908== possibly lost: 0 bytes in 0 blocks.
==3908== still reachable: 0 bytes in 0 blocks.
==3908== suppressed: 0 bytes in 0 blocks.