valgrind使用整理

valgrind使用整理

時間:20180703
參考文獻:
https://www.cnblogs.com/AndyStudy/p/6409287.html  valgrind 工具介紹和簡單的使用
https://blog.csdn.net/shixin_0125/article/details/78590796 linux工具之檢測內存泄漏-valgrind

https://www.cnblogs.com/zhoudayang/p/6110360.html  Valgrind 快速入門


0).前言

內存泄漏是c++程序常見的問題了,特別是服務類程序,當系統模塊過多或者邏輯複雜後,很難通過代碼看出內存泄漏;
valgrind是一個開源的,檢測c++程序內存泄漏有效工具,編譯時加上-g選項可以定位到代碼行,同時還檢查‘野指針’,檢查malloc與free是否匹配等功能;
Valgrind 是個開源的工具,功能很多。例如檢查內存泄漏工具---memcheck。
Valgrind工具組提供了一套調試與分析錯誤的工具包,能夠幫助你的程序工作的更加準確,更加快速。這些工具之中最有名的是Memcheck。它能夠識別很多C或者C++程序中內存相關的錯誤,這些錯誤會導致程序崩潰或者出現不可預知的行爲。

接下來會以最短的篇幅告訴你如何使用Memcheck來識別你寫的程序中的內存錯誤。你可以從用戶手冊中獲取Memcheck的完整文檔以及其他工具的使用說明。


1).Valgrind 安裝:

Ununtu:  apt-get install valgrind
嵌入式:(openwrt)
在內核菜單 make menuconfig
Development  --->
<*> valgrind......................... debugging and profiling tools for Linux 
<*>   valgrind-cachegrind                   
<*>   valgrind-callgrind               
<*>   valgrind-drd                          
<*>   valgrind-helgrind                                              
<*>   valgrind-massif. debugging and profiling tools for Linux (heap profiling)  

<*>   valgrind-vgdb.... debugging and profiling tools for Linux (GDB interface)


2).Valgrind 命令介紹:

用法: valgrind [options] prog-and-args 
[options]: 常用選項,適用於所有Valgrind工具
    -tool=<name> 最常用的選項。運行 valgrind中名爲toolname的工具。默認memcheck。
        memcheck ------> 這是valgrind應用最廣泛的工具,一個重量級的內存檢查器,能夠發現開發中絕大多數內存錯誤使用情況,比如:使用未初始化的內存,使用已經釋放了的內存,內存訪問越界等。
        callgrind ------> 它主要用來檢查程序中函數調用過程中出現的問題。
        cachegrind ------> 它主要用來檢查程序中緩存使用出現的問題。
        helgrind ------> 它主要用來檢查多線程程序中出現的競爭問題。
        massif ------> 它主要用來檢查程序中堆棧使用中出現的問題。
        extension ------> 可以利用core提供的功能,自己編寫特定的內存調試工具
    -h –help 顯示幫助信息。
    -version 顯示valgrind內核的版本,每個工具都有各自的版本。
    -q –quiet 安靜地運行,只打印錯誤信息。
    -v –verbose 更詳細的信息, 增加錯誤數統計。
    -trace-children=no|yes 跟蹤子線程? [no]
    -track-fds=no|yes 跟蹤打開的文件描述?[no]
    -time-stamp=no|yes 增加時間戳到LOG信息? [no]
    -log-fd=<number> 輸出LOG到描述符文件 [2=stderr]
    -log-file=<file> 將輸出的信息寫入到filename.PID的文件裏,PID是運行程序的進行ID
    -log-file-exactly=<file> 輸出LOG信息到 file
    -log-file-qualifier=<VAR> 取得環境變量的值來做爲輸出信息的文件名。 [none]

    -log-socket=ipaddr:port 輸出LOG到socket ,ipaddr:port

LOG信息輸出
    -xml=yes 將信息以xml格式輸出,只有memcheck可用
    -num-callers=<number> show <number> callers in stack traces [12]
    -error-limit=no|yes 如果太多錯誤,則停止顯示新錯誤? [yes]
    -error-exitcode=<number> 如果發現錯誤則返回錯誤代碼 [0=disable]
    -db-attach=no|yes 當出現錯誤,valgrind會自動啓動調試器gdb。[no]
    -db-command=<command> 啓動調試器的命令行選項[gdb -nw %f %p]


適用於Memcheck工具的相關選項:
    -leak-check=no|summary|full 要求對leak給出詳細信息? [summary]
    -leak-resolution=low|med|high how much bt merging in leak check [low]
    -show-reachable=no|yes show reachable blocks in leak check? [no]

4).測試程序main.c:

下面通過一個簡單的程序記錄valgrind的用法。
#include <stdio.h>
void f(){
    int * x = malloc(10 * sizeof(int));
    x[10] = 0;  //problem 1: heap block overrun
                //problem 2: memory leak -- x not freed
}
int main(){
    f();
    return 0;
}
 
編譯:
gcc main.c -g -o main
在編譯程序時開啓-g選項來引入調試信息,這樣Memcheck的錯誤信息中能夠準確的顯示問題代碼的序號。如果你能夠容忍一些性能損失,請使用-O0選項來編譯程序.使用-O1方式來編譯程序錯誤信息可能會不準確,雖然大體而言在使用-O1方式編譯的程序上使用Memcheck沒有問題,而且相比-O0方式編譯的程序而言性能大爲提升.不推薦使用-O2或者更高級別來編譯程序,因爲Memcheck偶爾會誤報值未初始化的錯誤.


下面是使用上述C代碼生成程序的makefile文件.
example:example.o
    gcc -o example example.o


example.o:a.c
    gcc -c -O0 -g -Wall a.c -o example.o


.PHONY:clean
clean:
    -rm -rf *.o example




5).調試命令:

命令:
valgrind -v --log-file=valgrind.log --tool=memcheck --leak-check=full --show-mismatched-frees=yes ./main
說明:加--log-file=valgrind.log 會在當前目錄下生成日誌文件,日誌不會在終端打印


[root@hui:/home/test/1test]#valgrind -v --log-file=valgrind.log --tool=memcheck --leak-check=full --show-mismatched-frees=yes ./main
[root@hui:/home/test/1test]#ls
main  main.c  main.c~  valgrind.log


最常用的命令格式:

valgrind --tool=memcheck --leak-check=full ./test


大多數的錯誤信息和下面的一致,下面展示了內存越界的錯誤:
==5753== Invalid write of size 4
==5753==    at 0x40053B: f (a.c:5)
==5753==    by 0x40054B: main (a.c:9)
==5753==  Address 0x51fc068 is 0 bytes after a block of size 40 alloc'd
==5753==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5753==    by 0x40052E: f (a.c:4)
==5753==    by 0x40054B: main (a.c:9)
注意:
每一個錯誤有很多信息, 請認真閱讀
5732是進程ID,這一般不重要
第一行Invalid write告訴你出現了哪一種錯誤.因爲內存泄露,程序向本不能訪問的內存進行了寫入操作.
在第一行之後緊跟的堆棧軌跡信息告訴你問題出現的位置. 堆棧軌跡信息可能會非常大,非常令人迷惑,特別是當你使用C++ STL的時候.推薦按照從下到上的順序進行閱讀.如果堆棧軌跡信息不夠,可以使用--num-callers選項來擴充堆棧軌跡信息.
代碼地址(例如:0x40054B) 一般不重要,但是有時在追蹤神祕的bug時會很有用.
一些錯誤信息有第二個部分描述了涉及到的內存地址.這一段表明了寫入的內存正好在malloc函數分配的內存的後面,對應代碼中的第9行.
推薦按照提示的順序來修復錯誤.因爲後面的錯誤可能因爲前面的錯誤導致.否則你會覺得Memcheck不好用.
內存泄露信息如下所示:
==5753== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5753==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5753==    by 0x40052E: f (a.c:4)
==5753==    by 0x40054B: main (a.c:9)
堆棧追蹤信息告訴你泄露的內存在哪裏分配的.Memcheck不能告訴你爲什麼內存會泄露.
有幾種不同的內存泄露方式,其中最重要的兩種類別是:
"definitely lost": 你的程序泄露了內存,請修復這個錯誤.
"probably lost": 你的程序泄露了內存,除非你在"玩弄"指針(例如移動指針到分配的內存塊的中間位置)
如果你不理解錯誤信息,請查詢用戶手冊中關於Memcheck錯誤信息的說明,其中舉例說明了Memcheck產生的所有類型的錯誤信息.
警告
Memcheck並不完美,它偶爾會誤報,有些機制可以抑制這些誤報.(請參考用戶手冊中的減少出錯章節).然而,他在99%的情況下都不會出錯,所以你需要謹慎地忽略它報告的錯誤信息.畢竟,你也不會忽略編譯器的報警信息.抑制機制對於你不能修改的庫代碼也有用.默認的抑制會影響庫代碼中的內存錯誤.
Memcheck不能夠偵測你程序中的所有內存錯誤.比如,他不能識別越界讀,或者對分配到棧區的數組的越界寫入.但是它能夠識別能導致你程序崩潰的大多數錯誤.
嘗試使你的程序更加清晰,這樣Memcheck檢測不出錯誤.當你達到這種狀態,你會更容易發現對程序的哪些修改導致Memcheck報告了新的錯誤.數年的Memcheck使用經驗說明,大型程序也能夠使用Memcheck. 比如KDE,Firefox等.




6).原理分析

原理:

 

 

 

 

參考網站:

http://www.linuxidc.com/Linux/2012-06/63754.htm
http://elinux.org/Valgrind (wiki)
http://blog.csdn.net/sduliulun/article/details/7732906
http://blog.csdn.net/gatieme/article/details/51959654(比較全面的介紹)
http://www.linuxidc.com/Linux/2012-06/63754.htm (非常詳細的介紹了每個工具的使用)


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章