1、valgrind檢測原理
valgrind 是一個(gè)提供了一些 debug 和優(yōu)化的工具的工具箱,可以使得你的程序減少內(nèi)存泄漏或者錯(cuò)誤訪問。valgrind 默認(rèn)使用 memcheck 去檢查內(nèi)存問題。memcheck 檢測內(nèi)存問題的原理如下圖所示:
Memcheck 能夠檢測出內(nèi)存問題,關(guān)鍵在于其建立了兩個(gè)全局表。
valid-value map:對于進(jìn)程的整個(gè)地址空間中的每一個(gè)字節(jié)(byte),都有與之對應(yīng)的 8 個(gè) bits;對于 CPU 的每個(gè)寄存器,也有一個(gè)與之對應(yīng)的 bit 向量。這些 bits 負(fù)責(zé)記錄該字節(jié)或者寄存器值是否具有有效的、已初始化的值。
valid-address map:對于進(jìn)程整個(gè)地址空間中的每一個(gè)字節(jié)(byte),還有與之對應(yīng)的 1 個(gè) bit,負(fù)責(zé)記錄該地址是否能夠被讀寫。在兩個(gè)全局表的基礎(chǔ)上,以如下方式進(jìn)行檢測:
當(dāng)要讀寫內(nèi)存中某個(gè)字節(jié)時(shí),首先檢查 valid-address map 中這個(gè)字節(jié)對應(yīng)的 A bit。
如果該A bit顯示該位置是無效位置,memcheck 則報(bào)告讀寫錯(cuò)誤。內(nèi)核(core)類似于一個(gè)虛擬的 CPU 環(huán)境,這樣當(dāng)內(nèi)存中的某個(gè)字節(jié)被加載到真實(shí)的 CPU 中時(shí),該字節(jié)對應(yīng)的 V bit (在 valid-value map 中) 也被加載到虛擬的 CPU 環(huán)境中。一旦寄存器中的值,被用來產(chǎn)生內(nèi)存地址,或者該值能夠影響程序輸出,則 memcheck 會檢查對應(yīng)的 V bits,如果該值尚未初始化,則會報(bào)告使用未初始化內(nèi)存錯(cuò)誤。
不過valgrind也不是萬能的,對于棧上的內(nèi)存空間操作就無法檢測到。
2、命令選項(xiàng)
基本命令:valgrind --leak-check=yes ./a.out arg1 arg2
為了能夠定位到源代碼的行,建議編譯時(shí)加上-g選項(xiàng),并選擇O0優(yōu)化
3、使用示例
示例代碼:
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); x[10]=1;//問題1,越界了 return0;//問題2,沒有釋放內(nèi)存 }
執(zhí)行valgrind檢測后的結(jié)果:
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)
結(jié)果解析如下:
==393==:執(zhí)行程序的進(jìn)程ID
Invalid write of size 4:表示發(fā)現(xiàn)一個(gè)錯(cuò)誤,這里顯示源代碼第6行有錯(cuò)誤,這里很明顯是越界了,所以顯示invalid write錯(cuò)誤
40 bytes in 1 blocks are definitely lost in loss record 1 of 1:內(nèi)存泄露錯(cuò)誤,泄漏的大小是10* sizeof(int)40byte。
LEAK summary也會顯示內(nèi)存泄漏的情況
4、分析常見內(nèi)存問題
4.1、寫入非法內(nèi)存地址
上面的例子已經(jīng)展示了這種情況,訪問分配的內(nèi)存區(qū)域之外的空間,valgrind會上報(bào)如下的錯(cuò)誤:
Invalid
write of size x
后跟調(diào)用棧信息
4.2、讀取非法內(nèi)存地址
和上一個(gè)情況類似,不同 的是讀取而不是寫入,錯(cuò)誤信息如下:
Invalid
read of size x
后跟調(diào)用棧信息
4.3、讀取未初始化內(nèi)存區(qū)域
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); inta=x[1]+1;//不初始化就使用內(nèi)存的值 free(x); returna; }
valgrind顯示如下錯(cuò)誤:
==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、內(nèi)存雙重釋放
示例:
#includeintmain() { int*x=(int*)malloc(10*sizeof(int)); free(x);//free兩次 free(x); return0; }
valgrind顯示如下錯(cuò)誤,顯示兩次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)
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3019瀏覽量
74003 -
程序
+關(guān)注
關(guān)注
117文章
3785瀏覽量
81003 -
Valgrind
+關(guān)注
關(guān)注
0文章
9瀏覽量
6807
原文標(biāo)題:Linux內(nèi)存泄漏調(diào)試?yán)?valgrind
文章出處:【微信號:嵌入式應(yīng)用研究院,微信公眾號:嵌入式應(yīng)用研究院】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論