關(guān)注「Linux大陸」,選擇「星標公眾號」一起進步!Valgrind簡介
Valgrind是一套Linux下,開放源代碼(GPL V2)的仿真調(diào)試工具的集合。Valgrind工具包包含多個工具,如Memcheck、Cachegrind、Helgrind、Callgrind、Massif。
Memcheck工具
Memcheck工具是Valgrind中最常用的工具,用來檢測程序中出現(xiàn)的內(nèi)存問題。它能檢測如下問題:
- 使用未初始化內(nèi)存;
- 使用釋放后的內(nèi)存;
- 使用超出malloc分配的內(nèi)存塊;
- 對堆棧的非法訪問;
- 內(nèi)存泄漏;
- 不正確的malloc/free或new/delete匹配;
- memcpy()相關(guān)函數(shù)中的dst和src指針重疊。
Cachegrind工具
Callgrind收集程序運行時的一些數(shù)據(jù),函數(shù)調(diào)用關(guān)系等信息,還可以有選擇地進行cache模擬。在運行結(jié)束時,它會把分析數(shù)據(jù)寫入一個文件。callgrind_annotate可以把這個文件的內(nèi)容轉(zhuǎn)化成可讀的形式。
Helgrind工具
它主要用來檢查多線程程序中出現(xiàn)的競爭問題。Helgrind尋找內(nèi)存中被多個線程訪問,而又沒有一貫加鎖的區(qū)域,這些區(qū)域往往是線程之間失去同步的地方,而且會導(dǎo)致難以發(fā)掘的錯誤。Helgrind實現(xiàn)了名為” Eraser” 的競爭檢測算法,并做了進一步改進,減少了報告錯誤的次數(shù)。
Callgrind工具
它模擬 CPU中的一級緩存I1,D1和L2二級緩存,能夠精確地指出程序中 cache的丟失和命中。如果需要,它還能夠為我們提供cache丟失次數(shù),內(nèi)存引用次數(shù),以及每行代碼,每個函數(shù),每個模塊,整個程序產(chǎn)生的指令數(shù)。這對優(yōu)化程序有很大的幫助。
Massif工具
堆棧分析器,它能測量程序在堆棧中使用了多少內(nèi)存,告訴我們堆塊,堆管理塊和棧的大小。Massif能幫助我們減少內(nèi)存的使用,在帶有虛擬內(nèi)存的現(xiàn)代系統(tǒng)中,它還能夠加速我們程序的運行,減少程序停留在交換區(qū)中的幾率。Valgrind由內(nèi)核(core)以及基于內(nèi)核的其他調(diào)試工具組成。其基于仿真方式對程序進行調(diào)試,它先于應(yīng)用程序獲取實際處理器的控制權(quán),并在實際處理器的基礎(chǔ)上仿真一個虛擬處理器,并使應(yīng)用程序運行于這個虛擬處理器之上,從而對應(yīng)用程序的運行進行監(jiān)視。應(yīng)用程序并不知道該處理器是虛擬的還是實際的,已經(jīng)編譯成二進制代碼的應(yīng)用程序并不用重新進行編譯,Valgrind 直接解釋二進制代碼使得應(yīng)用程序基于它運行,從而能夠檢查內(nèi)存操作時可能出現(xiàn)的錯誤。所以在Valgrind下運行的程序運行速度要慢得多,而且使用的內(nèi)存要多得多。因此,最好在性能好的機器上使用Valgrind,并且是在開發(fā)調(diào)試階段使用。
Valgrind安裝
Valgrind的安裝方式很簡單。我們首先查看一下我們的系統(tǒng)中有沒有Valgrind:顯然,我們這里的系統(tǒng)中沒有Valgrind,按提示輸入如下命令安裝即可:
sudo?apt?install?valgrind
另外,也可以通過下載源碼編譯、安裝。源碼地址:
?http://valgrind.org/?
下載源碼的命令:
wget?http://valgrind.org/downloads/valgrind-3.14.0.tar.bz2
Valgrind使用
準備一個有內(nèi)存泄漏、內(nèi)存越界問題的demo進行測試。為了方便,我們使用官方提供的一個經(jīng)典的測試demo:
「valgrind_test.c:」#include?
void?f(void)
{
?int*?x?=?malloc(10?*?sizeof(int));
?x[10]?=?0;???????//?problem?1:?heap?block?overrun
}?????????????????//?problem?2:?memory?leak?--?x?not?freed
int?main(void)
{
?f();
?return?0;
}
這份代碼存在兩個問題:
- 使用超出malloc分配的內(nèi)存。
- 內(nèi)存泄漏。
下面一起來使用valgrind的Memcheck工具來檢測這份程序。首先,我們使用-g編譯程序以包含調(diào)試信息,以便Memcheck的錯誤消息包含確切的行號。
gcc?-g?valgrind_test.c?-o?valgrind_test
使用valgrind檢測valgrind_test程序:
valgrind?--leak-check=yes?./valgrind_test
我們可以用
--tool
參數(shù)指明使用的工具,如:
--tool=memcheck
如果不明確設(shè)置
--tool
參數(shù),則valgrind的檢測工具默認使用的是Memcheck工具。
--leak-check=yes
選項打開詳細的內(nèi)存泄漏檢測器。我們執(zhí)行檢測工具之后的結(jié)果如:
==7407==?Memcheck,?a?memory?error?detector
==7407==?Copyright?(C)?2002-2017,?and?GNU?GPL'd,?by?Julian?Seward?et?al.
==7407==?Using?Valgrind-3.13.0?and?LibVEX;?rerun?with?-h?for?copyright?info
==7407==?Command:?./valgrind_test
==7407==?
==7407==?Invalid?write?of?size?4
==7407==????at?0x108668:?f?(valgrind_test.c:6)
==7407==????by?0x108679:?main?(valgrind_test.c:11)
==7407==??Address?0x522d068?is?0?bytes?after?a?block?of?size?40?alloc'd
==7407==????at?0x4C2FB0F:?malloc?(in?/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7407==????by?0x10865B:?f?(valgrind_test.c:5)
==7407==????by?0x108679:?main?(valgrind_test.c:11)
==7407==?
==7407==?
==7407==?HEAP?SUMMARY:
==7407==?????in?use?at?exit:?40?bytes?in?1?blocks
==7407==???total?heap?usage:?1?allocs,?0?frees,?40?bytes?allocated
==7407==?
==7407==?40?bytes?in?1?blocks?are?definitely?lost?in?loss?record?1?of?1
==7407==????at?0x4C2FB0F:?malloc?(in?/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7407==????by?0x10865B:?f?(valgrind_test.c:5)
==7407==????by?0x108679:?main?(valgrind_test.c:11)
==7407==?
==7407==?LEAK?SUMMARY:
==7407==????definitely?lost:?40?bytes?in?1?blocks
==7407==????indirectly?lost:?0?bytes?in?0?blocks
==7407==??????possibly?lost:?0?bytes?in?0?blocks
==7407==????still?reachable:?0?bytes?in?0?blocks
==7407==?????????suppressed:?0?bytes?in?0?blocks
==7407==?
==7407==?For?counts?of?detected?and?suppressed?errors,?rerun?with:?-v
==7407==?ERROR?SUMMARY:?2?errors?from?2?contexts?(suppressed:?0?from?0)
輸出結(jié)果包含有很多信息,我們可以很容易查看到了關(guān)鍵的信息:其中,輸出信息告訴我們無效地寫入了4個字節(jié),并且提示了可能出現(xiàn)問題的代碼行數(shù)。堆棧跟蹤告訴我們調(diào)用了一次malloc申請內(nèi)存,但并沒有free,并且指出了在哪里分配了內(nèi)存。另外,這里的
7407
表示的是進程ID號。內(nèi)存泄漏有幾種類型,最重要的兩類是:
- definitely lost(明確的泄漏)
- possibly lost(可能的泄漏)
其中,明確的泄漏必須要進行修復(fù)。以上就是關(guān)于valgrind最常用的Memcheck工具的簡單使用介紹,使用Memcheck工具有時候我們可以很清楚地檢測出程序存在的一些隱患。其它工具今后有用到的話再做分享,大家感興趣的話可以自行去研究學(xué)習(xí)。
Valgrind交叉編譯
1、下載valgrind源碼包:
wget?http://valgrind.org/downloads/valgrind-3.14.0.tar.bz2
2、修改valgrind里的configure文件:把 armv7 * ) 改成 armv7 * |arm)。3、生成Makefile
./configure?--host=arm-linux-gnueabihf?CC=/home/LinuxZn/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc?CXX=/home/LinuxZn/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g ?--prefix=$PWD/tmp
這個命令似乎很長,但并不難,只是加了幾個配置參數(shù)。這些配置參數(shù)怎么看?我們可以輸入
./configure --help
命令來查看支持的配置:下面我們依次來分析上面那個很長的命令:
- --host=arm-linux-gnueabihf:表明了我們最終可執(zhí)行文件運行的環(huán)境。
- CC=/home/LinuxZn/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc:這是指定我們的交叉編譯工具arm-linux-gnueabihf-gcc,這里直接給出絕對路徑。
- CXX=/home/LinuxZn/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g :這是指定我們的交叉編譯工具arm-linux-gnueabihf-g ,這里直接給出絕對路徑。
- --prefix=$PWD/tmp:指定安裝的路徑。表明安裝路徑在當(dāng)前路徑下的tmp文件夾中。
這時候已經(jīng)生成了Makefile文件:編譯、安裝:
make
make?install
安裝完成后tmp文件夾下的內(nèi)容為:這時候我們就可以把tmp整個文件夾拷到板子上使用了。tmp的大小為一百多兆,注意查看板子存儲空間夠不夠:我們可以配置板子上的valgrind環(huán)境。如果僅是臨時使用,可以這么用:
tmp/bin/valgrind?--tool=memcheck?--leak-check=yes?./valgrind_test
其中,tmp文件夾與與valgrind_test在同一路徑。這時候可能會報如下錯誤:
“valgrind:?failed?to?start?tool?‘memcheck’?for?platform?‘a(chǎn)rm-linux’:?No?such?file?or?directory”
這是因為valgrind需要依賴其動態(tài)庫,而沒有找到動態(tài)庫。因為是臨時測試,在valgrind_test路徑輸入如下命令進行設(shè)置:
export?VALGRIND_LIB="tmp/lib/valgrind"
這只是在當(dāng)前開發(fā)板終端生效,下次重新進入開發(fā)板終端需要重新設(shè)置。以上就是本次的分享。碼字不易,期待你的三連~大家平時都用些什么工具呢?歡迎留言分享~
參考資料
1、https://www.valgrind.org/docs/manual/quick-start.html#quick-start.prepare2、https://blog.csdn.net/andylauren/article/details/931897403、https://zhuanlan.zhihu.com/p/754163814、https://blog.csdn.net/listener51/article/details/86716497?depth_1-歷史文章:一文讀懂a(chǎn)pt、deb與背后的知識2021-06-12
實用 | 遠程gdb調(diào)試2021-06-20
有趣 | 最近遇到一個狡猾的bug,復(fù)盤分享2021-06-20