valgrind-yyds——memcheck检查程序中的内存问题,如泄漏、越界、非法指针等。
Valgrind 用戶手冊
文章目錄
- 1. valgrind概述
- 2. Valgrind 原理及安裝
- 2.1 [Valgrind 做了什么](https://www.valgrind.org/docs/manual/manual-core.html)
- 2.2 安裝
- 3 內(nèi)存檢測
- 3.1 memcheck 常用檢測指令
- 3 .2 內(nèi)存檢測結(jié)果
- 3 .3 內(nèi)存檢測含義
- 3 .4 內(nèi)存檢測更多例子
1. valgrind概述
Valgrind 是用于構(gòu)建動態(tài)分析工具的檢測框架。它帶有一組工具,每個(gè)工具都執(zhí)行某種調(diào)試、分析或類似任務(wù),以幫助您改進(jìn)程序。Valgrind 的架構(gòu)是模塊化的,因此可以輕松創(chuàng)建新工具,而不會干擾現(xiàn)有結(jié)構(gòu)。
- Memcheck是一個(gè)內(nèi)存錯(cuò)誤檢測器。它可以幫助您使您的程序,尤其是那些用 C 和 C++ 編寫的程序更加正確。
- Cachegrind是一個(gè)緩存和分支預(yù)測分析器。它可以幫助您使程序運(yùn)行得更快。
- Callgrind是一個(gè)調(diào)用圖生成緩存分析器。它與 Cachegrind 有一些重疊,但也收集了一些 Cachegrind 沒有的信息。
- Helgrind是一個(gè)線程錯(cuò)誤檢測器。它可以幫助您使多線程程序更加正確。
- DRD也是一個(gè)線程錯(cuò)誤檢測器。它類似于 Helgrind,但使用不同的分析技術(shù),因此可能會發(fā)現(xiàn)不同的問題。
- Massif是一個(gè)堆分析器。它可以幫助您使程序使用更少的內(nèi)存。
- DHAT是一種不同的堆分析器。它可以幫助您了解塊生命周期、塊利用率和布局效率低下的問題。
- BBV是一個(gè)實(shí)驗(yàn)性的 SimPoint 基本塊向量生成器。它對從事計(jì)算機(jī)體系結(jié)構(gòu)研究和開發(fā)的人很有用。
2. Valgrind 原理及安裝
2.1 Valgrind 做了什么
一方面,Memcheck 添加了代碼來檢查每次內(nèi)存訪問和計(jì)算的每個(gè)值,使其運(yùn)行速度比本機(jī)慢 10-50 倍。
另一種工具,稱為 Nulgrind 的最小工具根本不添加任何儀器,并且總共“僅”導(dǎo)致大約 4 倍的減速。
Valgrind 模擬程序執(zhí)行的每一條指令。因此,活動工具不僅會檢查或分析應(yīng)用程序中的代碼,還會檢查所有支持動態(tài)鏈接的庫,包括 C 庫、圖形庫等。
如果您正在使用錯(cuò)誤檢測工具,Valgrind可以檢測系統(tǒng)庫中的錯(cuò)誤,例如您必須使用的GNU C或X11庫。您可能對這些錯(cuò)誤不感興趣,因?yàn)槟赡軣o法控制這些代碼。因此,Valgrind允許您選擇性地抑制錯(cuò)誤
you can use the --gen-suppressions=yes option.指示Valgrind讀取描述內(nèi)聯(lián)信息的調(diào)試信息。這樣,就可以正確地顯示函數(shù)調(diào)用鏈,即使您的應(yīng)用程序是用內(nèi)聯(lián)方式編譯的。
2.2 安裝
建議從valgrind官網(wǎng)下載安裝,目前官網(wǎng)的最新包是3.16.1
$ mkdir valgrind-inst
$ cd valgrind-inst/
$ wget https://sourceware.org/pub/valgrind/valgrind-3.16.1.tar.bz2$ ls
valgrind-3.16.1.tar.bz2
//解壓后進(jìn)行安裝,可以指定安裝目錄,這樣的話記得設(shè)置環(huán)境變量
$ tar -xvf valgrind-3.16.1.tar.bz2
$ cd valgrind-3.16.1
$ ./configure --prefix=/usr/local/valgrind
$ make
$ make install
查看是否安裝成功
$ valgrind --version
valgrind-3.16.1
3 內(nèi)存檢測
3.1 memcheck 常用檢測指令
最常用的工具,用來檢測程序中出現(xiàn)的內(nèi)存問題,所有對內(nèi)存的讀寫都會被檢測到,一切對malloc、free、new、delete的調(diào)用都會被捕獲。所以,它能檢測以下問題:
1、使用未初始化的內(nèi)存。如果在定義一個(gè)變量時(shí)沒有賦初始值,后邊即使賦值了,使用這個(gè)變量的時(shí)候Memcheck也會報(bào)"uninitialised value"錯(cuò)誤。使用中會發(fā)現(xiàn),valgrind提示很多這個(gè)錯(cuò)誤,由于關(guān)注的是內(nèi)存泄漏問題,所以可以用--undef-value-errors=選項(xiàng)把這個(gè)錯(cuò)誤提示屏蔽掉,具體可以看后面的選項(xiàng)解釋。2、讀/寫釋放后的內(nèi)存塊;3、內(nèi)存讀寫越界(數(shù)組訪問越界/訪問已經(jīng)釋放的內(nèi)存),讀/寫超出malloc分配的內(nèi)存塊;4、讀/寫不適當(dāng)?shù)臈V袃?nèi)存塊;5、內(nèi)存泄漏,指向一塊內(nèi)存的指針永遠(yuǎn)丟失;6、不正確的malloc/free或new/delete匹配(重復(fù)釋放/使用不匹配的分配和釋放函數(shù));7、內(nèi)存覆蓋,memcpy()相關(guān)函數(shù)中的dst和src指針重疊。
valgrind --tool=memcheck --leak-check=full ./build/bin/aurora300_runner
valgrind --leak-check=full --show-leak-kinds=all ./build/bin/aurora300_runner
編譯后,用valgrind檢測程序。
如果設(shè)置了–leak-check=full,Memcheck會給出詳細(xì)的每個(gè)塊是在哪里分配,并且給出分配時(shí)函數(shù)調(diào)用堆棧(編譯的時(shí)候使用**-g選項(xiàng)**和去掉-o優(yōu)化選項(xiàng),就可以得到更詳細(xì)的函數(shù)信息,可以精確到代碼的某一行)。可以通過–show-leak-kinds選項(xiàng)來選擇要詳細(xì)報(bào)告哪幾種類型的錯(cuò)誤。Memcheck會把函數(shù)調(diào)用堆棧相同或相似的內(nèi)存塊信息,放到同一個(gè)條目來顯示,可以通過–leak-resolution來控制這個(gè)"相似"判斷的力度。
--tool: 是最常用的選項(xiàng),用于選擇使用valgrind工具集中的哪一個(gè)工具。默認(rèn)值為memcheck。--version: 用于打印valgrind的版本號-q/--quiet: 安靜的運(yùn)行,只打印錯(cuò)誤消息;-v/--verbose: 打印更詳細(xì)的信息;--trace-children: 是否跟蹤子進(jìn)程,默認(rèn)值為no;--track-fds: 是否追蹤打開的文件描述符,默認(rèn)為no--time-stamp=no|yes: 是否在打印出的每條消息之前加上時(shí)間戳信息。默認(rèn)值為no--log-file=<file>: 指定將消息打印到某個(gè)文件--default-suppressions: 加載默認(rèn)的抑制參數(shù)。--alignment: 指定malloc分配內(nèi)存時(shí)的最小對齊字節(jié)數(shù);如下的一些選項(xiàng)用于Memcheck工具:--leak-check=no|summary|full: 在退出時(shí)是否查找內(nèi)存泄露。默認(rèn)值為summary--show-leak-kinds=kind1,kind2,..: 顯示哪一種類型的內(nèi)存泄露。默認(rèn)顯示definite和possible這兩種;
3 .2 內(nèi)存檢測結(jié)果
output:
HEAP SUMMARY:
==6018== in use at exit: 10 bytes in 1 blocks
==6018== total heap usage: 1 allocs, 0 frees, 10 bytes allocated
==6018==
==6018== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==6018== at 0x4C2AC58: operator new[](unsigned long) (vg_replace_malloc.c:431)
==6018== by 0x40062E: func() (leak.cpp:4)
==6018== by 0x40063D: main (leak.cpp:8)
==72970== LEAK SUMMARY:
==72970== definitely lost: 0 bytes in 0 blocks
==72970== indirectly lost: 0 bytes in 0 blocks
==72970== possibly lost: 61,552 bytes in 71 blocks
==72970== still reachable: 152,585 bytes in 2,436 blocks
==72970== of which reachable via heuristic:
==72970== newarray : 792 bytes in 3 blocks
==72970== suppressed: 0 bytes in 0 blocks
==72970== Reachable blocks (those to which a pointer was found) are not shown.
==72970== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==72970==
==72970== For counts of detected and suppressed errors, rerun with: -v
==72970== Use --track-origins=yes to see where uninitialised values come from
==72970== ERROR SUMMARY: 70078 errors from 51 contexts (suppressed: 0 from 0)
3 .3 內(nèi)存檢測含義
結(jié)果說明:
先看看輸出信息中的HEAP SUMMARY,它表示程序在堆上分配內(nèi)存的情況,其中的1 allocs 表示程序分配了 1 次內(nèi)存,0 frees表示程序釋放了 0 次內(nèi)存,10 bytes allocated表示分配了 10 個(gè)字節(jié)的內(nèi)存。 另外,Valgrind 也會報(bào)告程序是在哪個(gè)位置發(fā)生內(nèi)存泄漏。
上面LEAK SUMMARY會打印5種不同的類型,這里我們簡單介紹一下:
結(jié)果說明:
- definitely lost:
明確丟失的內(nèi)存。程序中存在內(nèi)存泄露,應(yīng)盡快修復(fù)。當(dāng)程序結(jié)束時(shí)如果一塊動態(tài)分配的內(nèi)存沒有被釋放并且通過程序內(nèi)的指針變量均無法訪問這塊內(nèi)存則會報(bào)這個(gè)錯(cuò)誤; - indirectly lost:
間接丟失。當(dāng)使用了含有指針成員的類或結(jié)構(gòu)體時(shí)可能會報(bào)這個(gè)錯(cuò)誤。這類錯(cuò)誤無需直接修復(fù),它們總是與definitely lost一起出現(xiàn),只要修復(fù)definitely lost即可。 - possibly lost:
可能丟失。大多數(shù)情況下應(yīng)視為與definitely lost一樣需要盡快修復(fù),除非你的程序讓一個(gè)指針指向一塊動態(tài)分配的內(nèi)存(但不是這塊內(nèi)存的起始地址),然后通過運(yùn)算得到這塊內(nèi)存的起始地址,再釋放它。當(dāng)程序結(jié)束時(shí)如果一塊動態(tài)分配的內(nèi)存沒有被釋放并且通過程序內(nèi)的指針變量均無法訪問這塊內(nèi)存的起始地址,但可以訪問其中的某一部分?jǐn)?shù)據(jù),則會報(bào)這個(gè)錯(cuò)誤。 - still reachable:
可以訪問,未丟失但也未釋放。如果程序是正常結(jié)束的,那么它可能不會造成程序崩潰,但長時(shí)間運(yùn)行有可能耗盡系統(tǒng)資源。
3 .4 內(nèi)存檢測更多例子
總結(jié)
以上是生活随笔為你收集整理的valgrind-yyds——memcheck检查程序中的内存问题,如泄漏、越界、非法指针等。的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【NEON 】初探
- 下一篇: 速度与激情特别行动啥时候下架