年前,寫了使用mtrace定位內(nèi)存泄漏,在留言中,有讀者提到了希望介紹valgrind,那好,今天就介紹使用valgrind定位內(nèi)存泄漏。
大約2-3年前,楊同學(xué)讓我?guī)妥瞿M面試,他求職的是C++崗位,我問了這樣一個(gè)問題:在你的項(xiàng)目中,你是如何定位內(nèi)存泄漏的呢?
結(jié)果,他對這個(gè)問題很陌生,感覺從來沒有思考過相關(guān)問題,也沒有做這方面的準(zhǔn)備,自然就沒法正確作答,這讓我覺得有點(diǎn)吃驚。
如果準(zhǔn)備得不成功,那就要準(zhǔn)備失敗了。在筆試面試中,遇到內(nèi)存泄漏的定位問題,如果連valgrind都說不出來,那就很容易歇菜了。
總之,無論是為了找工作,還是為了實(shí)際工作中的問題,都很有必要熟練使用valgrind,那么,我們一起來看看這玩意兒是怎么回事。
有的朋友可能還不熟悉linux, 沒關(guān)系,和濤哥一起來,先來man valgrind一下:
ubuntu@VM-0-15-ubuntu:~$ man valgrindVALGRIND(1) Release 3.11.0 VALGRIND(1)NAMEvalgrind - a suite of tools for debugging and profiling programsSYNOPSISvalgrind [valgrind-options] [your-program] [your-program-options]DESCRIPTIONValgrind is a flexible program for debugging and profiling Linux executables. It consists of a core, whichprovides a synthetic CPU in software, and a series of debugging and profiling tools. The architecture is modular,so that new tools can be created easily and without disturbing the existing structure.Some of the options described below work with all Valgrind tools, and some only work with a few or one. Thesection MEMCHECK OPTIONS and those below it describe tool-specific options.This manual page covers only basic usage and options. For more comprehensive information, please see the HTMLdocumentation on your system: $INSTALL/share/doc/valgrind/html/index.html, or online:http://www.valgrind.org/docs/manual/index.html.TOOL SELECTION OPTIONSThe single most important option.--tool=<toolname> [default: memcheck]Run the Valgrind tool called toolname, e.g. memcheck, cachegrind, callgrind, helgrind, drd, massif, lackey,none, exp-sgcheck, exp-bbv, exp-dhat, etc.
可以看到,valgrind是一款程序調(diào)試和分析的工具,其最重要的功能是內(nèi)存檢查,而我們今天要介紹的內(nèi)存泄漏檢查,便是其一。
valgrind除了檢查內(nèi)存泄漏外,還能檢查內(nèi)存越界、內(nèi)存異常釋放等諸多問題。這也是當(dāng)年在騰訊面試中,面試官補(bǔ)充提到的問題。
具體來說,就是可以通過valgrind的toolname參數(shù),來定制使用valgrind功能。下面,一起來看下toolname參數(shù)的部分選項(xiàng)。
memcheck: 檢查內(nèi)存問題,如泄漏、越界、異常釋放
callgrind: 分析程序性能
cachegrind: 分析cache
helgrind: 分析多線程競爭
massif: 分析堆
接下來,我們介紹使用valgrind的toolname參數(shù)中的memcheck, 并用實(shí)際例子來看看如何定位內(nèi)存泄漏。
開發(fā)人員都應(yīng)該知道,內(nèi)存泄漏是一個(gè)很嚴(yán)重的問題,不容忽視。說起來有點(diǎn)悲催,我大學(xué)畢業(yè)時(shí),居然還沒聽說過內(nèi)存泄漏。
往事不堪回首,那就不回首了。言歸正傳,進(jìn)入正題。我們來寫一段有內(nèi)存泄漏的程序,如下(只有malloc, 沒有free)
char* getMemory(){char *p = (char *)malloc(30);return p;}int main(){char *p = getMemory();p = NULL;return 0;}
很明顯,這段程序存在內(nèi)存泄漏。有的讀者總要說,一眼就看出來的問題,你用valgrind整那么復(fù)雜干啥?
很顯然,這種同學(xué)缺乏實(shí)戰(zhàn)經(jīng)驗(yàn),對敵人沒有清醒的認(rèn)識(shí)。幾十萬行的代碼,你能用肉眼很明顯看出內(nèi)存泄漏?
也有同學(xué)要說,先申請堆內(nèi)存,賦值給p指針, 然后又不使用p指針, 這不是無聊嗎(一位讀者之前提的問題)?
同學(xué),實(shí)際項(xiàng)目中肯定要使用p啊!而在本文中,我只是用一個(gè)demo例子,來實(shí)戰(zhàn)說明內(nèi)存泄漏及其定位方法。
話不多說,繼續(xù)介紹valgrind吧!先來編譯一下(注意:編譯時(shí)帶上-g參數(shù),便于定位出具體的代碼行),然后用valgrind分析:
ubuntu@VM-0-15-ubuntu:~$ g++ -g test.cppubuntu@VM-0-15-ubuntu:~$ubuntu@VM-0-15-ubuntu:~$ubuntu@VM-0-15-ubuntu:~$ valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./a.out==31560== Memcheck, a memory error detector==31560== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.==31560== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info==31560== Command: ./a.out==31560====31560====31560== HEAP SUMMARY:==31560== in use at exit: 30 bytes in 1 blocks==31560== total heap usage: 1 allocs, 0 frees, 30 bytes allocated==31560====31560== 30 bytes in 1 blocks are definitely lost in loss record 1 of 1==31560== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)==31560== by 0x400537: getMemory() (test.cpp:5)==31560== by 0x40054E: main (test.cpp:11)==31560====31560== LEAK SUMMARY:==31560== definitely lost: 30 bytes in 1 blocks==31560== indirectly lost: 0 bytes in 0 blocks==31560== possibly lost: 0 bytes in 0 blocks==31560== still reachable: 0 bytes in 0 blocks==31560== suppressed: 0 bytes in 0 blocks==31560====31560== For counts of detected and suppressed errors, rerun with: -v==31560== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Oh, so nice啊,可以清晰地看到,內(nèi)存definitely lost了,并且知道是getMemory函數(shù)中,且在第5行,于是乎,找到了內(nèi)存泄漏的地方了。
接下來,我們準(zhǔn)備修復(fù)這個(gè)內(nèi)存泄漏問題,然后使用valgrind進(jìn)行再次驗(yàn)證。
修復(fù)內(nèi)存泄漏后,代碼為:
char* getMemory(){char *p = (char *)malloc(30);return p;}int main(){char *p = getMemory();if(p != NULL){free(p);p = NULL;}return 0;}
編譯一下,并再次使用valgrind來驗(yàn)證:
ubuntu@VM-0-15-ubuntu:~$ g++ -g test.cppubuntu@VM-0-15-ubuntu:~$ubuntu@VM-0-15-ubuntu:~$ubuntu@VM-0-15-ubuntu:~$ valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./a.out==2839== Memcheck, a memory error detector==2839== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.==2839== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info==2839== Command: ./a.out==2839====2839====2839== HEAP SUMMARY:==2839== in use at exit: 0 bytes in 0 blocks==2839== total heap usage: 1 allocs, 1 frees, 30 bytes allocated==2839====2839== All heap blocks were freed -- no leaks are possible==2839====2839== For counts of detected and suppressed errors, rerun with: -v==2839== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)ubuntu@VM-0-15-ubuntu:~$
快來看啊,All heap blocks were freed -- no leaks are possible, 所有的堆內(nèi)存都釋放了,不存在任何內(nèi)存泄漏。看到這句話后,總算是心安了。
關(guān)于內(nèi)存泄露的問題,我們已經(jīng)介紹過mtrace和valgrind兩種工具來調(diào)試和定位,也歡迎大家分享自己使用過的有效方法。
風(fēng)在起,云在涌,心情在跳動(dòng)。金三銀四,已經(jīng)開始。祝大家工作順利,祝跳槽的朋友,薪資翻倍,offer多多,挑得花眼。
·················· END ··················
點(diǎn)擊關(guān)注公眾號,免費(fèi)領(lǐng)學(xué)習(xí)資料