天天看點

Valgrind 使用簡單說明Valgrind 介紹

調不盡的記憶體洩露,用不完的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 工具

  1. -tool=<name> 最常用的選項。運作 valgrind 中名為toolname的工具。預設memcheck。
  2. h –help 顯示幫助資訊。
  3. -version 顯示 valgrind 核心的版本,每個工具都有各自的版本。
  4. q –quiet 安靜地運作,隻列印錯誤資訊。
  5. v –verbose 更詳細的資訊, 增加錯誤數統計。
  6. -trace-children=no|yes 跟蹤子線程? [no]
  7. -track-fds=no|yes 跟蹤打開的檔案描述?[no]
  8. -time-stamp=no|yes 增加時間戳到LOG資訊? [no]
  9. -log-fd=<number> 輸出LOG到描述符檔案 [2=stderr]
  10. -log-file=<file> 将輸出的資訊寫入到filename.PID的檔案裡,PID是運作程式的進行ID
  11. -log-file-exactly=<file> 輸出LOG資訊到 file
  12. -log-file-qualifier=<VAR> 取得環境變量的值來做為輸出資訊的檔案名。 [none]
  13. -log-socket=ipaddr:port 輸出LOG到socket ,ipaddr:port

LOG資訊輸出

  1. -xml=yes 将資訊以xml格式輸出,隻有memcheck可用
  2. -num-callers=<number> show <number> callers in stack traces [12]
  3. -error-limit=no|yes 如果太多錯誤,則停止顯示新錯誤? [yes]
  4. -error-exitcode=<number> 如果發現錯誤則傳回錯誤代碼 [0=disable]
  5. -db-attach=no|yes 當出現錯誤, valgrind 會自動啟動調試器gdb。[no]
  6. -db-command=<command> 啟動調試器的指令行選項[gdb -nw %f %p]

适用于Memcheck工具的相關選項:

  1. -leak-check=no|summary|full 要求對leak給出詳細資訊? [summary]
  2. -leak-resolution=low|med|high how much bt merging in leak check [low]
  3. -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.      

繼續閱讀