1、valgrind檢測原理
valgrind 是一個提供了一些 debug 和優(yōu)化的工具的工具箱,可以使得你的程序減少內存泄漏或者錯誤訪問。valgrind 默認使用 memcheck 去檢查內存問題。memcheck 檢測內存問題的原理如下圖所示:
Memcheck 能夠檢測出內存問題,關鍵在于其建立了兩個全局表。
valid-value map:對于進程的整個地址空間中的每一個字節(jié)(byte),都有與之對應的 8 個 bits;對于 CPU 的每個寄存器,也有一個與之對應的 bit 向量。這些 bits 負責記錄該字節(jié)或者寄存器值是否具有有效的、已初始化的值。
valid-address map:對于進程整個地址空間中的每一個字節(jié)(byte),還有與之對應的 1 個 bit,負責記錄該地址是否能夠被讀寫。在兩個全局表的基礎上,以如下方式進行檢測:
當要讀寫內存中某個字節(jié)時,首先檢查 valid-address map 中這個字節(jié)對應的 A bit。
如果該A bit顯示該位置是無效位置,memcheck 則報告讀寫錯誤。內核(core)類似于一個虛擬的 CPU 環(huán)境,這樣當內存中的某個字節(jié)被加載到真實的 CPU 中時,該字節(jié)對應的 V bit (在 valid-value map 中) 也被加載到虛擬的 CPU 環(huán)境中。一旦寄存器中的值,被用來產生內存地址,或者該值能夠影響程序輸出,則 memcheck 會檢查對應的 V bits,如果該值尚未初始化,則會報告使用未初始化內存錯誤。
不過valgrind也不是萬能的,對于棧上的內存空間操作就無法檢測到。
2、命令選項
基本命令:valgrind --leak-check=yes ./a.out arg1 arg2
為了能夠定位到源代碼的行,建議編譯時加上-g選項,并選擇O0優(yōu)化
3、使用示例
示例代碼:
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); x[10]=1;//問題1,越界了 return0;//問題2,沒有釋放內存 }
執(zhí)行valgrind檢測后的結果:
barret@Barret-PC:~$valgrind--leak-check=yes./a.out ==393==Memcheck,amemoryerrordetector ==393==Copyright(C)2002-2017,andGNUGPL'd,byJulianSewardetal. ==393==UsingValgrind-3.15.0andLibVEX;rerunwith-hforcopyrightinfo ==393==Command:./a.out ==393== ==393==Invalidwriteofsize4 ==393==at0x10916B:main(a.cpp:6) ==393==Address0x4a47068is0bytesafterablockofsize40alloc'd ==393==at0x483B7F3:malloc(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==393==by0x10915E:main(a.cpp:5) ==393== ==393== ==393==HEAPSUMMARY: ==393==inuseatexit:40bytesin1blocks ==393==totalheapusage:1allocs,0frees,40bytesallocated ==393== ==393==40bytesin1blocksaredefinitelylostinlossrecord1of1 ==393==at0x483B7F3:malloc(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==393==by0x10915E:main(a.cpp:5) ==393== ==393==LEAKSUMMARY: ==393==definitelylost:40bytesin1blocks ==393==indirectlylost:0bytesin0blocks ==393==possiblylost:0bytesin0blocks ==393==stillreachable:0bytesin0blocks ==393==suppressed:0bytesin0blocks ==393== ==393==Forlistsofdetectedandsuppressederrors,rerunwith:-s ==393==ERRORSUMMARY:2errorsfrom2contexts(suppressed:0from0)
結果解析如下:
==393==:執(zhí)行程序的進程ID
Invalid write of size 4:表示發(fā)現(xiàn)一個錯誤,這里顯示源代碼第6行有錯誤,這里很明顯是越界了,所以顯示invalid write錯誤
40 bytes in 1 blocks are definitely lost in loss record 1 of 1:內存泄露錯誤,泄漏的大小是10* sizeof(int)40byte。
LEAK summary也會顯示內存泄漏的情況
4、分析常見內存問題
4.1、寫入非法內存地址
上面的例子已經展示了這種情況,訪問分配的內存區(qū)域之外的空間,valgrind會上報如下的錯誤:
Invalid
write of size x
后跟調用棧信息
4.2、讀取非法內存地址
和上一個情況類似,不同 的是讀取而不是寫入,錯誤信息如下:
Invalid
read of size x
后跟調用棧信息
4.3、讀取未初始化內存區(qū)域
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); inta=x[1]+1;//不初始化就使用內存的值 free(x); returna; }
valgrind顯示如下錯誤:
==427==Syscallparamexit_group(status)**containsuninitialisedbyte(s)** ==427==at0x4938136:Exit(exit.c:31) ==427==by0x489BB41:__run_exit_handlers(exit.c:132) ==427==by0x489BBDF:exit(exit.c:139) ==427==by0x48790B9:(belowmain)(libc-start.c:342)
4.4、內存雙重釋放
示例:
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); free(x);//free兩次 free(x); return0; }
valgrind顯示如下錯誤,顯示兩次free的位置:
==436==Invalidfree()/delete/delete[]/realloc() ==436==**at0x483CA3F:free(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==436==by0x10919A:main(a.cpp:7) ==436==Address0x4a47040is0bytesinsideablockofsize40free'd ==436==at0x483CA3F:free(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==436==by0x10918E:main(a.cpp:6)** ==436==Blockwasalloc'dat ==436==at0x483B7F3:malloc(in/usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==436==by0x10917E:main(a.cpp:5)
-
內存
+關注
關注
8文章
3025瀏覽量
74054 -
程序
+關注
關注
117文章
3787瀏覽量
81049 -
Valgrind
+關注
關注
0文章
9瀏覽量
6811
原文標題:Linux內存泄漏調試利器-valgrind
文章出處:【微信號:嵌入式應用研究院,微信公眾號:嵌入式應用研究院】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論