原文地址:http://www.cnblogs.com/napoleon_liu/articles/2001802.html
調(diào)不盡的內(nèi)存泄漏,用不完的Valgrind 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. 運行./autogen.sh設(shè)置環(huán)境(需要標準的autoconf工具)(可選) 6. ./configure;配置Valgrind,生成MakeFile文件,具體參數(shù)信息詳見INSTALL文件。一般只需要設(shè)置--prefix=/where/you/want/it/installed 7. Make;編譯Valgrind 8. make install;安裝Valgrind Valgrind包含的工具 Valgrind支持很多工具:memcheck,addrcheck,cachegrind,Massif,helgrind和Callgrind等。在運行Valgrind時,你必須指明想用的工具,如果省略工具名,默認運行memcheck。 1、memcheck memcheck探測程序中內(nèi)存管理存在的問題。它檢查所有對內(nèi)存的讀/寫操作,并截取所有的malloc/new/free/delete調(diào)用。因此memcheck工具能夠探測到以下問題: 1)使用未初始化的內(nèi)存 2)讀/寫已經(jīng)被釋放的內(nèi)存 3)讀/寫內(nèi)存越界 4)讀/寫不恰當(dāng)?shù)膬?nèi)存??臻g 5)內(nèi)存泄漏 6)使用malloc/new/new[]和free/delete/delete[]不匹配。 7)src和dst的重疊 2、cachegrind cachegrind是一個cache剖析器。它模擬執(zhí)行CPU中的L1, D1和L2 cache,因此它能很精確的指出代碼中的cache未命中。如果你需要,它可以打印出cache未命中的次數(shù),內(nèi)存引用和發(fā)生cache未命中的每一行代碼,每一個函數(shù),每一個模塊和整個程序的摘要。如果你要求更細致的信息,它可以打印出每一行機器碼的未命中次數(shù)。在x86和amd64上, cachegrind通過CPUID自動探測機器的cache配置,所以在多數(shù)情況下它不再需要更多的配置信息了。 3、helgrind helgrind查找多線程程序中的競爭數(shù)據(jù)。helgrind查找內(nèi)存地址,那些被多于一條線程訪問的內(nèi)存地址,但是沒有使用一致的鎖就會被查出。這表示這些地址在多線程間訪問的時候沒有進行同步,很可能會引起很難查找的時序問題。 它主要用來檢查多線程程序中出現(xiàn)的競爭問題。Helgrind 尋找內(nèi)存中被多個線程訪問,而又沒有一貫加鎖的區(qū)域,這些區(qū)域往往是線程之間失去同步的地方,而且會導(dǎo)致難以發(fā)掘的錯誤。Helgrind實現(xiàn)了名為”Eraser” 的競爭檢測算法,并做了進一步改進,減少了報告錯誤的次數(shù)。 4、Callgrind Callgrind收集程序運行時的一些數(shù)據(jù),函數(shù)調(diào)用關(guān)系等信息,還可以有選擇地進行cache 模擬。在運行結(jié)束時,它會把分析數(shù)據(jù)寫入一個文件。callgrind_annotate可以把這個文件的內(nèi)容轉(zhuǎn)化成可讀的形式。 一般用法: $valgrind --tool=callgrind ./sec_infod 會在當(dāng)前目錄下生成callgrind.out.[pid], 如果我們想結(jié)束程序, 可以 $killall callgrind 然后我們可以用 $callgrind_annotate --auto=yes callgrind.out.[pid] > log $vi log 5、Massif 堆棧分析器,它能測量程序在堆棧中使用了多少內(nèi)存,告訴我們堆塊,堆管理塊和棧的大小。Massif能幫助我們減少內(nèi)存的使用,在帶有虛擬內(nèi)存的現(xiàn)代系統(tǒng)中,它還能夠加速我們程序的運行,減少程序停留在交換區(qū)中的幾率。 6、lackey lackey是一個示例程序,以其為模版可以創(chuàng)建你自己的工具。在程序結(jié)束后,它打印出一些基本的關(guān)于程序執(zhí)行統(tǒng)計數(shù)據(jù)。 Valgrind的參數(shù) 用法: valgrind [options] prog-and-args [options]: 常用選項,適用于所有Valgrind工具 --tool=<name> 最常用的選項。運行 valgrind中名為toolname的工具。默認memcheck。 -h --help 顯示所有選項的幫助,包括內(nèi)核和選定的工具兩者。 --version 顯示valgrind內(nèi)核的版本,每個工具都有各自的版本。 -q --quiet 安靜地運行,只打印錯誤信息。 --verbose 更詳細的信息。 --trace-children=<yes|no> 跟蹤子線程? [default: no] --track-fds=<yes|no> 跟蹤打開的文件描述?[default: no] --time-stamp=<yes|no> 增加時間戳到LOG信息? [default: no] --log-fd=<number> 輸出LOG到描述符文件 [2=stderr] --log-file=<file> 將輸出的信息寫入到filename.PID的文件里,PID是運行程序的進行ID --log-file-exactly=<file> 輸出LOG信息到 file LOG信息輸出 --xml=yes 將信息以xml格式輸出,只有memcheck可用 --num-callers=<number> show <number> callers in stack traces [12] --error-exitcode=<number> 如果發(fā)現(xiàn)錯誤則返回錯誤代碼 [0=disable] --db-attach=<yes|no> 當(dāng)出現(xiàn)錯誤,valgrind會自動啟動調(diào)試器gdb。[default: no] --db-command=<command> 啟動調(diào)試器的命令行選項[gdb -nw %f %p] 適用于Memcheck工具的相關(guān)選項: --leak-check=<no|summary|full> 要求對leak給出詳細信息? Leak是指,存在一塊沒有被引用的內(nèi)存空間,或沒有被釋放的內(nèi)存空間,如summary,只反饋一些總結(jié)信息,告訴你有多少個malloc,多少個free 等;如果是full將輸出所有的leaks,也就是定位到某一個malloc/free。 [default: summary] --show-reachable=<yes|no> 如果為no,只輸出沒有引用的內(nèi)存leaks,或指向malloc返回的內(nèi)存塊中部某處的leaks [default: no] 更詳細的參數(shù)指令見附錄A。 Valgrind的使用 首先,在編譯程序的時候打開調(diào)試模式(gcc編譯器的-g選項)。如果沒有調(diào)試信息,即使最好的valgrind工具也將中能夠猜測特定的代碼是屬于哪一個函數(shù)。打開調(diào)試選項進行編譯后再用valgrind檢查,valgrind將會給你的個詳細的報告,比如哪一行代碼出現(xiàn)了內(nèi)存泄漏。 當(dāng)檢查的是C++程序的時候,還應(yīng)該考慮另一個選項 -fno-inline。它使得函數(shù)調(diào)用鏈很清晰,這樣可以減少你在瀏覽大型C++程序時的混亂。比如在使用這個選項的時候,用memcheck檢查openoffice就很容易。當(dāng)然,你可能不會做這項工作,但是使用這一選項使得valgrind生成更精確的錯誤報告和減少混亂。 一些編譯優(yōu)化選項(比如-O2或者更高的優(yōu)化選項),可能會使得memcheck提交錯誤的未初始化報告,因此,為了使得valgrind的報告更精確,在編譯的時候最好不要使用優(yōu)化選項。 如果程序是通過腳本啟動的,可以修改腳本里啟動程序的代碼,或者使用--trace-children=yes選項來運行腳本。 下面是用memcheck檢查sample.c的例子 這里用到的示例程序文件名為:sample.c(如下所示),選用的編譯器為gcc。 生成可執(zhí)行程序 gcc –g sample.c –o sample 圖1 運行Valgrind valgrind --tool=memcheck ./sample 以下是運行上述命令后的輸出 圖2 左邊顯示類似行號的數(shù)字(10297)表示的是 Process ID。 最上面的紅色方框表示的是 valgrind 的版本信息。 中間的紅色方框表示 valgrind 通過運行被測試程序,發(fā)現(xiàn)的內(nèi)存問題。通過閱讀這些信息,可以發(fā)現(xiàn): l 這是一個對內(nèi)存的非法寫操作,非法寫操作的內(nèi)存是4 bytes。 l 發(fā)生錯誤時的函數(shù)堆棧,以及具體的源代碼行號。 l 非法寫操作的具體地址空間。 最下面的紅色方框是對發(fā)現(xiàn)的內(nèi)存問題和內(nèi)存泄漏問題的總結(jié)。內(nèi)存泄漏的大?。?0 bytes)也能夠被檢測出來。 Valgrind的示例 例1.使用未初始化的內(nèi)存 代碼如下 #include <stdio.h>
例2.內(nèi)存讀寫越界 代碼如下 #include <stdlib.h>
例3.src和dst內(nèi)存覆蓋 代碼如下 #include <stdlib.h> #include <stdio.h> #include <string.h> int main(int argc,char *argv[]) { char x[50]; int i; for(i=0;i<50;i++) {x[i]=i;} strncpy(x+20,x,20); //Good strncpy(x+20,x,21); //Overlap x[39]=’\0’; strcpy(x,x+20); //Good x[39]=40; x[40]=’\0’; strcpy(x,x+20); //Overlap return 0; } Valgrind提示如下 ==24139== Source and destination overlap in strncpy(0x7FEFFFC09, 0x7FEFFFBF5, 21) ==24139== at 0x4A0724F: strncpy (mc_replace_strmem.c:116) ==24139== by 0x400527: main (sample3.c:10) ==24139== ==24139== Source and destination overlap in strcpy(0x7FEFFFBE0, 0x7FEFFFBF4) ==24139== at 0x4A06E47: strcpy (mc_replace_strmem.c:106) ==24139== by 0x400555: main (sample3.c:15) ==24139== ==24139== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 5 from 1) ==24139== malloc/free: in use at exit: 0 bytes in 0 blocks. ==24139== malloc/free: 0 allocs, 0 frees, 0 bytes allocated. ==24139== For counts of detected errors, rerun with: -v ==24139== All heap blocks were freed -- no leaks are possible. 例4.動態(tài)內(nèi)存管理錯誤 常見的內(nèi)存分配方式分三種:靜態(tài)存儲,棧上分配,堆上分配。全局變量屬于靜態(tài)存儲,它們是在編譯時就被分配了存儲空間,函數(shù)內(nèi)的局部變量屬于棧上分配,而最靈活的內(nèi)存使用方式當(dāng)屬堆上分配,也叫做內(nèi)存動態(tài)分配了。常用的內(nèi)存動態(tài)分配函數(shù)包括:malloc, alloc, realloc, new等,動態(tài)釋放函數(shù)包括free, delete。 一旦成功申請了動態(tài)內(nèi)存,我們就需要自己對其進行內(nèi)存管理,而這又是最容易犯錯誤的。常見的內(nèi)存動態(tài)管理錯誤包括: l 申請和釋放不一致 由于 C++ 兼容 C,而 C 與 C++ 的內(nèi)存申請和釋放函數(shù)是不同的,因此在 C++ 程序中,就有兩套動態(tài)內(nèi)存管理函數(shù)。一條不變的規(guī)則就是采用 C 方式申請的內(nèi)存就用 C 方式釋放;用 C++ 方式申請的內(nèi)存,用 C++ 方式釋放。也就是用 malloc/alloc/realloc 方式申請的內(nèi)存,用 free 釋放;用 new 方式申請的內(nèi)存用 delete 釋放。在上述程序中,用 malloc 方式申請了內(nèi)存卻用 delete 來釋放,雖然這在很多情況下不會有問題,但這絕對是潛在的問題。 l 申請和釋放不匹配 申請了多少內(nèi)存,在使用完成后就要釋放多少。如果沒有釋放,或者少釋放了就是內(nèi)存泄露;多釋放了也會產(chǎn)生問題。上述程序中,指針p和pt指向的是同一塊內(nèi)存,卻被先后釋放兩次。 l 釋放后仍然讀寫 本質(zhì)上說,系統(tǒng)會在堆上維護一個動態(tài)內(nèi)存鏈表,如果被釋放,就意味著該塊內(nèi)存可以繼續(xù)被分配給其他部分,如果內(nèi)存被釋放后再訪問,就可能覆蓋其他部分的信息,這是一種嚴重的錯誤,上述程序第16行中就在釋放后仍然寫這塊內(nèi)存。 下面的一段程序,就包括了內(nèi)存動態(tài)管理中常見的錯誤。 #include <stdlib.h> #include <stdio.h> int main(int argc,char *argv[]) { char *p=(char*)malloc(10); char *pt=p; int i; for(i=0;i<10;i++) {p[i]=’z’;} delete p; p[1]=’a’; free(pt); return 0; } Valgrind提示如下 ==25811== Mismatched free() / delete / delete [] ==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244) ==25811== by 0x400654: main (sample4.c:9) ==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 alloc'd ==25811== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==25811== by 0x400620: main (sample4.c:4) ==25811== ==25811== Invalid write of size 1 ==25811== at 0x40065D: main (sample4.c:10) ==25811== Address 0x4C2F031 is 1 bytes inside a block of size 10 free'd ==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244) ==25811== by 0x400654: main (sample4.c:9) ==25811== ==25811== Invalid free() / delete / delete[] ==25811== at 0x4A0541E: free (vg_replace_malloc.c:233) ==25811== by 0x400668: main (sample4.c:11) ==25811== Address 0x4C2F030 is 0 bytes inside a block of size 10 free'd ==25811== at 0x4A05130: operator delete(void*) (vg_replace_malloc.c:244) ==25811== by 0x400654: main (sample4.c:9) ==25811== ==25811== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 5 from 1) ==25811== malloc/free: in use at exit: 0 bytes in 0 blocks. ==25811== malloc/free: 1 allocs, 2 frees, 10 bytes allocated. ==25811== For counts of detected errors, rerun with: -v ==25811== All heap blocks were freed -- no leaks are possible. 例5.內(nèi)存泄漏 代碼如下 #include <stdlib.h> int main() { char *x = (char*)malloc(20); char *y = (char*)malloc(20); x=y; free(x); free(y); return 0; } Valgrind提示如下 ==19013== Invalid free() / delete / delete[] ==19013== at 0x4A0541E: free (vg_replace_malloc.c:233) ==19013== by 0x4004F5: main (sample5.c:8) ==19013== Address 0x4C2E078 is 0 bytes inside a block of size 20 free'd ==19013== at 0x4A0541E: free (vg_replace_malloc.c:233) ==19013== by 0x4004EC: main (sample5.c:7) ==19013== ==19013== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1) ==19013== malloc/free: in use at exit: 20 bytes in 1 blocks. ==19013== malloc/free: 2 allocs, 2 frees, 40 bytes allocated. ==19013== For counts of detected errors, rerun with: -v ==19013== searching for pointers to 1 not-freed blocks. ==19013== checked 66,584 bytes. ==19013== ==19013== LEAK SUMMARY: ==19013== definitely lost: 20 bytes in 1 blocks. ==19013== possibly lost: 0 bytes in 0 blocks. ==19013== still reachable: 0 bytes in 0 blocks. ==19013== suppressed: 0 bytes in 0 blocks. ==19013== Use --leak-check=full to see details of leaked memory. 例6.非法寫/讀 代碼如下 int main() { int i, *x; x = (int *)malloc(10*sizeof(int)); for (i=0; i<11; i++) x[i] = i; free(x); } Valgrind提示如下 ==21483== Invalid write of size 4 ==21483== at 0x4004EA: main (sample6.c:6) ==21483== Address 0x4C2E058 is 0 bytes after a block of size 40 alloc'd ==21483== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==21483== by 0x4004C9: main (sample6.c:4) ==21483== ==21483== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1) ==21483== malloc/free: in use at exit: 0 bytes in 0 blocks. ==21483== malloc/free: 1 allocs, 1 frees, 40 bytes allocated. ==21483== For counts of detected errors, rerun with: -v ==21483== All heap blocks were freed -- no leaks are possible. 例7.無效指針 代碼如下 #include <stdlib.h> int main() { char *x = malloc(10); x[10] = 'a'; free(x); return 0; } Valgrind提示如下 ==15262== Invalid write of size 1 ==15262== at 0x4004D6: main (sample7.c:5) ==15262== Address 0x4C2E03A is 0 bytes after a block of size 10 alloc'd ==15262== at 0x4A05809: malloc (vg_replace_malloc.c:149) ==15262== by 0x4004C9: main (sample7.c:4) ==15262== ==15262== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1) ==15262== malloc/free: in use at exit: 0 bytes in 0 blocks. ==15262== malloc/free: 1 allocs, 1 frees, 10 bytes allocated. ==15262== For counts of detected errors, rerun with: -v ==15262== All heap blocks were freed -- no leaks are possible. 例8.重復(fù)釋放 代碼如下 #include <stdlib.h> int main() { char *x = malloc(10); free(x); free(x); return 0; } Valgrind提示如下 ==15005== Invalid free() / delete / delete[] ==15005== at 0x4A0541E: free (vg_replace_malloc.c:233) ==15005== by 0x4004DF: main (sample8.c:6) ==15005== Address 0x4C2E030 is 0 bytes inside a block of size 10 free'd ==15005== at 0x4A0541E: free (vg_replace_malloc.c:233) ==15005== by 0x4004D6: main (sample8.c:5) ==15005== ==15005== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 1) ==15005== malloc/free: in use at exit: 0 bytes in 0 blocks. ==15005== malloc/free: 1 allocs, 2 frees, 10 bytes allocated. ==15005== For counts of detected errors, rerun with: -v ==15005== All heap blocks were freed -- no leaks are possible. Valgrind的局限 l Valgrind不對靜態(tài)數(shù)組(分配在棧上)進行邊界檢查。如果在程序中聲明了一個數(shù)組: int main() { char x[10]; x[11] = 'a'; } Valgrind則不會警告你,你可以把數(shù)組改為動態(tài)在堆上分配的數(shù)組,這樣就可能進行邊界檢查了。這個方法好像有點得不償失的感覺。 l Valgrind占用了更多的內(nèi)存--可達兩倍于你程序的正常使用量。如果你用Valgrind來檢測使用大量內(nèi)存的程序就會遇到問題,它可能會用很長的時間來運行測試。大多數(shù)情況下,這都不是問題,即使速度慢也僅是檢測時速度慢,如果你用Valgrind來檢測一個正常運行時速度就很慢的程序,這下問題就大了。 Valgrind不可能檢測出你在程序中犯下的所有錯誤--如果你不檢查緩沖區(qū)溢出,Valgrind也不會告訴你代碼寫了它不應(yīng)該寫的內(nèi)存。 附錄A:參數(shù)指令 基本選項: 這些選項對所有工具都有效。 -h --help 顯示所有選項的幫助,包括內(nèi)核和選定的工具兩者。 --help-debug 和--help相同,并且還能顯示通常只有Valgrind的開發(fā)人員使用的調(diào)試選項。 --version 顯示Valgrind內(nèi)核的版本號。工具可以有他們自已的版本號。這是一種保證工具只在它們可以運行的內(nèi)核上工作的一種設(shè)置。這樣可以減少在工具和內(nèi)核之間版本兼容性導(dǎo)致奇怪問題的概率。 -q --quiet 安靜的運行,只打印錯誤信息。在進行回歸測試或者有其它的自動化測試機制時會非常有用。 -v --verbose 顯示詳細信息。在各個方面顯示你的程序的額外信息,例如:共享對象加載,使用的重置,執(zhí)行引擎和工具的進程,異常行為的警告信息。重復(fù)這個標記可以增加詳細的級別。 -d 調(diào)試Valgrind自身發(fā)出的信息。通常只有Valgrind開發(fā)人員對此感興趣。重復(fù)這個標記可以產(chǎn)生更詳細的輸出。如果你希望發(fā)送一個bug報告,通過-v -v -d -d生成的輸出會使你的報告更加有效。 --tool=<toolname> [default: memcheck] 運行toolname指定的Valgrind,例如,Memcheck, Addrcheck, Cachegrind,等等。 --trace-children=<yes|no> [default: no] 當(dāng)這個選項打開時,Valgrind會跟蹤到子進程中。這經(jīng)常會導(dǎo)致困惑,而且通常不是你所期望的,所以默認這個選項是關(guān)閉的。 --track-fds=<yes|no> [default: no] 當(dāng)這個選項打開時,Valgrind會在退出時打印一個打開文件描述符的列表。每個文件描述符都會打印出一個文件是在哪里打開的棧回溯,和任何與此文件描述符相關(guān)的詳細信息比如文件名或socket信息。 --time-stamp=<yes|no> [default: no] 當(dāng)這個選項打開時,每條信息之前都有一個從程序開始消逝的時間,用天,小時,分鐘,秒和毫秒表示。 --log-fd=<number> [default: 2, stderr] 指定Valgrind把它所有的消息都輸出到一個指定的文件描述符中去。默認值2, 是標準錯誤輸出(stderr)。注意這可能會干擾到客戶端自身對stderr的使用, Valgrind的輸出與客戶程序的輸出將穿插在一起輸出到stderr。 --log-file=<filename> 指定Valgrind把它所有的信息輸出到指定的文件中。實際上,被創(chuàng)建文件的文件名是由filename、'.'和進程號連接起來的(即<filename>.<pid>),從而每個進程創(chuàng)建不同的文件。 --log-file-exactly=<filename> 類似于--log-file,但是后綴".pid"不會被添加。如果設(shè)置了這個選項,使用Valgrind跟蹤多個進程,可能會得到一個亂七八糟的文件。 --log-file-qualifier=<VAR> 當(dāng)和--log-file一起使用時,日志文件名將通過環(huán)境變量$VAR來篩選。這對于MPI程序是有益的。更多的細節(jié),查看手冊2.3節(jié) "注解"。 --log-socket=<ip-address:port-number> 指定Valgrind輸出所有的消息到指定的IP,指定的端口。當(dāng)使用1500端口時,端口有可能被忽略。如果不能建立一個到指定端口的連接,Valgrind將輸出寫到標準錯誤(stderr)。這個選項經(jīng)常和一個Valgrind監(jiān)聽程序一起使用。更多的細節(jié),查看手冊2.3節(jié) "注解"。 錯誤相關(guān)選項: 這些選項適用于所有產(chǎn)生錯誤的工具,比如Memcheck, 但是Cachegrind不行。 --xml=<yes|no> [default: no] 當(dāng)這個選項打開時,輸出將是XML格式。這是為了使用Valgrind的輸出做為輸入的工具,例如GUI前端更加容易些。目前這個選項只在Memcheck時生效。 --xml-user-comment=<string> 在XML開頭 附加用戶注釋,僅在指定了--xml=yes時生效,否則忽略。 --demangle=<yes|no> [default: yes] 打開/關(guān)閉C++的名字自動解碼。默認打開。當(dāng)打開時,Valgrind將嘗試著把編碼過的C++名字自動轉(zhuǎn)回初始狀態(tài)。這個解碼器可以處理g++版本為2.X,3.X或4.X生成的符號。一個關(guān)于名字編碼解碼重要的事實是,禁止文件中的解碼函數(shù)名仍然使用他們未解碼的形式。Valgrind在搜尋可用的禁止條目時不對函數(shù)名解碼,因為這將使禁止文件內(nèi)容依賴于Valgrind的名字解碼機制狀態(tài),會使速度變慢,且無意義。 --num-callers=<number> [default: 12] 默認情況下,Valgrind顯示12層函數(shù)調(diào)用的函數(shù)名有助于確定程序的位置。可以通過這個選項來改變這個數(shù)字。這樣有助在嵌套調(diào)用的層次很深時確定程序的位置。注意錯誤信息通常只回溯到最頂上的4個函數(shù)。(當(dāng)前函數(shù),和它的3個調(diào)用者的位置)。所以這并不影響報告的錯誤總數(shù)。這個值的最大值是50。注意高的設(shè)置會使Valgrind運行得慢,并且使用更多的內(nèi)存,但是在嵌套調(diào)用層次比較高的程序中非常實用。 --error-limit=<yes|no> [default: yes] 當(dāng)這個選項打開時,在總量達到10,000,000,或者1,000個不同的錯誤,Valgrind停止報告錯誤。這是為了避免錯誤跟蹤機制在錯誤很多的程序下變成一個巨大的性能負擔(dān)。 --error-exitcode=<number> [default: 0] 指定如果Valgrind在運行過程中報告任何錯誤時的退出返回值,有兩種情況;當(dāng)設(shè)置為默認值(零)時,Valgrind返回的值將是它模擬運行的程序的返回值。當(dāng)設(shè)置為非零值時,如果Valgrind發(fā)現(xiàn)任何錯誤時則返回這個值。在Valgrind做為一個測試工具套件的部分使用時這將非常有用,因為使測試工具套件只檢查Valgrind返回值就可以知道哪些測試用例Valgrind報告了錯誤。 --show-below-main=<yes|no> [default: no] 默認地,錯誤時的?;厮莶伙@示main()之下的任何函數(shù)(或者類似的函數(shù)像glibc的__libc_start_main(),如果main()沒有出現(xiàn)在棧回溯中);這些大部分都是令人厭倦的C庫函數(shù)。如果打開這個選項,在main()之下的函數(shù)也將會顯示。 --suppressions=<filename> [default: $PREFIX/lib/valgrind/default.supp] 指定一個額外的文件讀取不需要理會的錯誤;你可以根據(jù)需要使用任意多的額外文件。 --gen-suppressions=<yes|no|all> [default: no] 當(dāng)設(shè)置為yes時,Valgrind將會在每個錯誤顯示之后自動暫停并且打印下面這一行:---- Print suppression ? --- [Return/N/n/Y/y/C/c] ----這個提示的行為和--db-attach選項(見下面)相同。如果選擇是,Valgrind會打印出一個錯誤的禁止條目,你可以把它剪切然后粘帖到一個文件,如果不希望在將來再看到這個錯誤信息。當(dāng)設(shè)置為all時,Valgrind會對每一個錯誤打印一條禁止條目,而不向用戶詢問。這個選項對C++程序非常有用,它打印出編譯器調(diào)整過的名字。注意打印出來的禁止條目是盡可能的特定的。如果需要把類似的條目歸納起來,比如在函數(shù)名中添加通配符。并且,有些時候兩個不同的錯誤也會產(chǎn)生同樣的禁止條目,這時Valgrind就會輸出禁止條目不止一次,但是在禁止條目的文件中只需要一份拷貝(但是如果多于一份也不會引起什么問題)。并且,禁止條目的名字像<在這兒輸入一個禁止條目的名字>;名字并不是很重要,它只是和-v選項一起使用打印出所有使用的禁止條目記錄。 --db-attach=<yes|no> [default: no] 當(dāng)這個選項打開時,Valgrind將會在每次打印錯誤時暫停并打出如下一行:---- Attach to debugger ? --- [Return/N/n/Y/y/C/c] ---- 按下回車,或者N、回車,n、回車,Valgrind不會對這個錯誤啟動調(diào)試器。按下Y、回車,或者y、回車,Valgrind會啟動調(diào)試器并設(shè)定在程序運行的這個點。當(dāng)調(diào)試結(jié)束時,退出,程序會繼續(xù)運行。在調(diào)試器內(nèi)部嘗試繼續(xù)運行程序,將不會生效。按下C、回車,或者c、回車,Valgrind不會啟動一個調(diào)試器,并且不會再次詢問。注意:--db-attach=yes與--trace-children=yes有沖突。你不能同時使用它們。Valgrind在這種情況下不能啟動。 2002.05: 這是一個歷史的遺留物,如果這個問題影響到你,請發(fā)送郵件并投訴這個問題。 2002.11:如果你發(fā)送輸出到日志文件或者到網(wǎng)絡(luò)端口,我猜這不會讓你有任何感覺。不須理會。 --db-command=<command> [default: gdb -nw %f %p] 通過--db-attach指定如何使用調(diào)試器。默認的調(diào)試器是gdb.默認的選項是一個運行時擴展Valgrind的模板。 %f會用可執(zhí)行文件的文件名替換,%p會被可執(zhí)行文件的進程ID替換。 這指定了Valgrind將怎樣調(diào)用調(diào)試器。默認選項不會因為在構(gòu)造時是否檢測到了GDB而改變,通常是/usr/bin/gdb.使用這個命令,你可以指定一些調(diào)用其它的調(diào)試器來替換。 給出的這個命令字串可以包括一個或多個%p %f擴展。每一個%p實例都被解釋成將調(diào)試的進程的PID,每一個%f實例都被解釋成要調(diào)試的進程的可執(zhí)行文件路徑。 --input-fd=<number> [default: 0, stdin] 使用--db-attach=yes和--gen-suppressions=yes選項,在發(fā)現(xiàn)錯誤時,Valgrind會停下來去讀取鍵盤輸入。默認地,從標準輸入讀取,所以關(guān)閉了標準輸入的程序會有問題。這個選項允許你指定一個文件描述符來替代標準輸入讀取。 --max-stackframe=<number> [default: 2000000] 棧的最大值。如果棧指針的偏移超過這個數(shù)量,Valgrind則會認為程序是切換到了另外一個棧執(zhí)行。如果在程序中有大量的棧分配的數(shù)組,你可能需要使用這個選項。valgrind保持對程序棧指針的追蹤。如果棧指針的偏移超過了這個數(shù)量,Valgrind假定你的程序切換到了另外一個棧,并且Memcheck行為與棧指 針的偏移沒有超出這個數(shù)量將會不同。通常這種機制運轉(zhuǎn)得很好。然而,如果你的程序在棧上申請了大的結(jié)構(gòu),這種機制將會表現(xiàn)得愚蠢,并且Memcheck將會報告大量的非法棧內(nèi)存訪問。這個選項允許把這個閥值設(shè)置為其它值。應(yīng)該只在Valgrind的調(diào)試輸出中顯示需要這么做時才使用這個選項。在這種情況下,它會告訴你應(yīng)該指定的新的閥值。普遍地,在棧中分配大塊的內(nèi)存是一個壞的主意。因為這很容易用光你的棧空間,尤其是在內(nèi)存受限的系統(tǒng)或者支持大量小堆棧的線程的系統(tǒng)上,因為Memcheck執(zhí)行的錯誤檢查,對于堆上的數(shù)據(jù)比對棧上的數(shù)據(jù)要高效很多。如果你使用這個選項,你可能希望考慮重寫代碼在堆上分配內(nèi)存而不是在棧上分配。 MALLOC()相關(guān)的選項: 對于使用自有版本的malloc() (例如Memcheck和massif),下面的選項可以使用。 --alignment=<number> [default: 8] 默認Valgrind的malloc(),realloc(), 等等,是8字節(jié)對齊地址的。這是大部分處理器的標準。然而,一些程序可能假定malloc()等總是返回16字節(jié)或更多對齊的內(nèi)存。提供的數(shù)值必須在8和4096區(qū)間之內(nèi),并且必須是2的冪數(shù)。 非通用選項: 這些選項可以用于所有的工具,它們影響Valgrind core的幾個特性。大部分人不會用到這些選項。 --run-libc-freeres=<yes|no> [default: yes] GNU C庫(libc.so),所有程序共用的,可能會分配一部分內(nèi)存自已用。通常在程序退出時釋放內(nèi)存并不麻煩 -- 這里沒什么問題,因為Linux內(nèi)核在一個進程退出時會回收進程全部的資源,所以這只是會造成速度慢。glibc的作者認識到這樣會導(dǎo)致內(nèi)存檢查器,像Valgrind,在退出時檢查內(nèi)存錯誤的報告glibc的內(nèi)存泄漏問題,為了避免這個問題,他們提供了一個__libc_freeres()例程特別用來讓glibc釋放分配的所有內(nèi)存。因此Memcheck在退出時嘗試著去運行__libc_freeres()。不幸的是,在glibc的一些版本中,__libc_freeres是有bug會導(dǎo)致段錯誤的。這在Red Hat 7.1上有特別聲明。所以,提供這個選項來決定是否運行__libc_freeres。如果你的程序看起來在Valgrind上運行得很好,但是在退出時發(fā)生段錯誤,你可能需要指定--run-libc-freeres=no來修正,這將可能錯誤的報告libc.so的內(nèi)存泄漏。 --sim-hints=hint1,hint2,... 傳遞雜湊的提示給Valgrind,輕微的修改模擬行為的非標準或危險方式,可能有助于模擬奇怪的特性。默認沒有提示打開。小心使用!目前已知的提示有: l lax-ioctls: 對ioctl的處理非常不嚴格,唯一的假定是大小是正確的。不需要在寫時緩沖區(qū)完全的初始化。沒有這個,用大量的奇怪的ioctl命令來使用一些設(shè)備驅(qū)動將會非常煩人。 l enable-inner:打開某些特殊的效果,當(dāng)運行的程序是Valgrind自身時。 --kernel-variant=variant1,variant2,... 處理系統(tǒng)調(diào)用和ioctls在這個平臺的默認核心上產(chǎn)生不同的變量。這有助于運行在改進過的內(nèi)核或者支持非標準的ioctls上。小心使用。如果你不理解這個選項做的是什么那你幾乎不需要它。已經(jīng)知道的變量有: l bproc: 支持X86平臺上的sys_broc系統(tǒng)調(diào)用。這是為了運行在BProc,它是標準Linux的一個變種,有時用來構(gòu)建集群。 --show-emwarns=<yes|no> [default: no] 當(dāng)這個選項打開時,Valgrind在一些特定的情況下將對CPU仿真產(chǎn)生警告。通常這些都是不引人注意的。 --smc-check=<none|stack|all> [default: stack] 這個選項控制Valgrind對自我修改的代碼的檢測。Valgrind可以不做檢測,可以檢測棧中自我修改的代碼,或者任意地方檢測自我修改的代碼。注意默認選項是捕捉絕大多數(shù)情況,到目前我們了解的情況為止。使用all選項時會極大的降低速度。(但是用none選項運行極少影響速度,因為對大多數(shù)程序,非常少的代碼被添加到棧中) 調(diào)試VALGRIND選項: 還有一些選項是用來調(diào)試Valgrind自身的。在運行一般的東西時不應(yīng)該需要的。如果你希望看到選項列表,使用--help-debug選項。 內(nèi)存檢查選項: --leak-check=<no|summary|yes|full> [default: summary] 當(dāng)這個選項打開時,當(dāng)客戶程序結(jié)束時查找內(nèi)存泄漏。內(nèi)存泄漏意味著有用malloc分配內(nèi)存塊,但是沒有用free釋放,而且沒有指針指向這塊內(nèi)存。這樣的內(nèi)存塊永遠不能被程序釋放,因為沒有指針指向它們。如果設(shè)置為summary,Valgrind會報告有多少內(nèi)存泄漏發(fā)生了。如果設(shè)置為full或yes,Valgrind給出每一個獨立的泄漏的詳細信息。 --show-reachable=<yes|no> [default: no] 當(dāng)這個選項關(guān)閉時,內(nèi)存泄漏檢測器只顯示沒有指針指向的內(nèi)存塊,或者只能找到指向塊中間的指針。當(dāng)這個選項打開時,內(nèi)存泄漏檢測器還報告有指針指向的內(nèi)存塊。這些塊是最有可能出現(xiàn)內(nèi)存泄漏的地方。你的程序可能,至少在原則上,應(yīng)該在退出前釋放這些內(nèi)存塊。這些有指針指向的內(nèi)存塊和沒有指針指向的內(nèi)存塊,或者只有內(nèi)部指針指向的塊,都可能產(chǎn)生內(nèi)存泄漏,因為實際上沒有一個指向塊起始的指針可以拿來釋放,即使你想去釋放它。 --leak-resolution=<low|med|high> [default: low] 在做內(nèi)存泄漏檢查時,確定memcheck將怎么樣考慮不同的棧是相同的情況。當(dāng)設(shè)置為low時,只需要前兩層棧匹配就認為是相同的情況;當(dāng)設(shè)置為med,必須要四層棧匹配,當(dāng)設(shè)置為high時,所有層次的棧都必須匹配。對于hardcore內(nèi)存泄漏檢查,你很可能需要使用--leak-resolution=high和--num-callers=40或者更大的數(shù)字。注意這將產(chǎn)生巨量的信息,這就是為什么默認選項是四個調(diào)用者匹配和低分辨率的匹配。注意--leak-resolution= 設(shè)置并不影響memcheck查找內(nèi)存泄漏的能力。它只是改變了結(jié)果如何輸出。 --freelist-vol=<number> [default: 5000000] 當(dāng)客戶程序使用free(C中)或者delete(C++)釋放內(nèi)存時,這些內(nèi)存并不是馬上就可以用來再分配的。這些內(nèi)存將被標記為不可訪問的,并被放到一個已釋放內(nèi)存的隊列中。這樣做的目的是,使釋放的內(nèi)存再次被利用的點盡可能的晚。這有利于memcheck在內(nèi)存塊釋放后這段重要的時間檢查對塊不合法的訪問。這個選項指定了隊列所能容納的內(nèi)存總?cè)萘?,以字?jié)為單位。默認的值是5000000字節(jié)。增大這個數(shù)目會增加memcheck使用的內(nèi)存,但同時也增加了對已釋放內(nèi)存的非法使用的檢測概率。 --workaround-gcc296-bugs=<yes|no> [default: no] 當(dāng)這個選項打開時,假定讀寫棧指針以下的一小段距離是gcc 2.96的bug,并且不報告為錯誤。距離默認為256字節(jié)。注意gcc 2.96是一些比較老的Linux發(fā)行版(RedHat 7.X)的默認編譯器,所以你可能需要使用這個選項。如果不是必要請不要使用這個選項,它可能會使一些真正的錯誤溜掉。一個更好的解決辦法是使用較新的,修正了這個bug的gcc/g++版本。 --partial-loads-ok=<yes|no> [default: no] 控制memcheck如何處理從地址讀取時字長度,字對齊,因此哪些字節(jié)是可以尋址的,哪些是不可以尋址的。當(dāng)設(shè)置為yes是,這樣的讀取并不拋出一個尋址錯誤。而是從非法地址讀取的V字節(jié)顯示為未定義,訪問合法地址仍然是像平常一樣映射到內(nèi)存。設(shè)置為no時,從部分錯誤的地址讀取與從完全錯誤的地址讀取同樣處理:拋出一個非法地址錯誤,結(jié)果的V字節(jié)顯示為合法數(shù)據(jù)。注意這種代碼行為是違背ISO C/C++標準,應(yīng)該被認為是有問題的。如果可能,這種代碼應(yīng)該修正。這個選項應(yīng)該只是做為一個最后考慮的方法。 --undef-value-errors=<yes|no> [default: yes] 控制memcheck是否檢查未定義值的危險使用。當(dāng)設(shè)為yes時,Memcheck的行為像Addrcheck, 一個輕量級的內(nèi)存檢查工具,是Valgrind的一個部分,它并不檢查未定義值的錯誤。使用這個選項,如果你不希望看到未定義值錯誤。 CACHEGRIND選項: 手動指定I1/D1/L2緩沖配置,大小是用字節(jié)表示的。這三個必須用逗號隔開,中間沒有空格,例如: valgrind --tool=cachegrind --I1=65535,2,64你可以指定一個,兩個或三個I1/D1/L2緩沖。如果沒有手動指定,每個級別使用普通方式(通過CPUID指令得到緩沖配置,如果失敗,使用默認值)得到的配置。 --I1=<size>,<associativity>,<line size> 指定第一級指令緩沖的大小,關(guān)聯(lián)度和行大小。 --D1=<size>,<associativity>,<line size> 指定第一級數(shù)據(jù)緩沖的大小,關(guān)聯(lián)度和行大小。 --L2=<size>,<associativity>,<line size> 指定第二級緩沖的大小,關(guān)聯(lián)度和行大小。 CALLGRIND選項: --heap=<yes|no> [default: yes] 當(dāng)這個選項打開時,詳細的追蹤堆的使用情況。關(guān)閉這個選項時,massif.pid.txt或massif.pid.html將會非常的簡短。 --heap-admin=<number> [default: 8] 每個塊使用的管理字節(jié)數(shù)。這只能使用一個平均的估計值,因為它可能變化。glibc使用的分配器每塊需要4~15字節(jié),依賴于各方面的因素。管理已經(jīng)釋放的塊也需要空間,盡管massif不計算這些。 --stacks=<yes|no> [default: yes] 當(dāng)打開時,在剖析信息中包含棧信息。多線程的程序可能有多個棧。 --depth=<number> [default: 3] 詳細的堆信息中調(diào)用過程的深度。增加這個值可以給出更多的信息,但是massif會更使這個程序運行得慢,使用更多的內(nèi)存,并且產(chǎn)生一個大的massif.pid.txt或者massif.pid.hp文件。 --alloc-fn=<name> 指定一個分配內(nèi)存的函數(shù)。這對于使用malloc()的包裝函數(shù)是有用的,可以用它來填充原來無效的上下文信息。(這些函數(shù)會給出無用的上下文信息,并在圖中給出無意義的區(qū)域)。指定的函數(shù)在上下文中被忽略,例如,像對malloc()一樣處理。這個選項可以在命令行中重復(fù)多次,指定多個函數(shù)。 --format=<text|html> [default: text] 產(chǎn)生text或者HTML格式的詳細堆信息,文件的后綴名使用.txt或者.html。 HELGRIND選項: --private-stacks=<yes|no> [default: no] 假定線程棧是私有的。 --show-last-access=<yes|some|no> [default: no] 顯示最后一次字訪問出錯的位置。 LACKEY選項: --fnname=<name> [default: _dl_runtime_resolve()] 對<name>函數(shù)計數(shù)。 --detailed-counts=<no|yes> [default: no] 對讀取,存儲和alu操作計數(shù)。 完 |
|
來自: 娛天樂 > 《valgrind》