Valgrind 快速入門


1. 介紹

Valgrind工具組提供了一套調試與分析錯誤的工具包,能夠幫助你的程序工作的更加准確,更加快速。這些工具之中最有名的是Memcheck。它能夠識別很多C或者C++程序中內存相關的錯誤,這些錯誤會導致程序崩潰或者出現不可預知的行為。

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

2. 准備你的程序

在編譯程序時開啟-g選項來引入調試信息,這樣Memcheck的錯誤信息中能夠准確的顯示問題代碼的序號。如果你能夠容忍一些性能損失,請使用-O0選項來編譯程序.使用-O1方式來編譯程序錯誤信息可能會不准確,雖然大體而言在使用-O1方式編譯的程序上使用Memcheck沒有問題,而且相比-O0方式編譯的程序而言性能大為提升.不推薦使用-O2或者更高級別來編譯程序,因為Memcheck偶爾會誤報值未初始化的錯誤.

3.在Memcheck下運行你的程序

如果你的程序按照以下方式運行:

myprog arg1 arg2

請使用下述命令來執行內存檢查:

valgrind --leak-check=yes myprog arg1 arg2

Memcheck是默認的工具,開啟--leak-check選項會啟動內存泄露檢查.

你的程序會比正常運行慢很多(大概20到30倍),並且會使用更多的內存.Memcheck會記錄檢測到的內存錯誤和內存泄露信息.

4.解釋Memcheck的輸出信息

這是我們的用於示例的C程序代碼,其文件名為a.c,這段代碼中有一個內存錯誤和內存泄露問題.

#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;
}

下面是使用上述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

使用下述命令檢查程序中的內存錯誤:

valgrind --leak-check=yes ./example

大多數的錯誤信息和下面的一致,下面展示了內存越界的錯誤:

==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產生的所有類型的錯誤信息.

5.警告

Memcheck並不完美,它偶爾會誤報,有些機制可以抑制這些誤報.(請參考用戶手冊中的減少出錯章節).然而,他在99%的情況下都不會出錯,所以你需要謹慎地忽略它報告的錯誤信息.畢竟,你也不會忽略編譯器的報警信息.抑制機制對於你不能修改的庫代碼也有用.默認的抑制會影響庫代碼中的內存錯誤.

Memcheck不能夠偵測你程序中的所有內存錯誤.比如,他不能識別越界讀,或者對分配到棧區的數組的越界寫入.但是它能夠識別能導致你程序崩潰的大多數錯誤.

嘗試使你的程序更加清晰,這樣Memcheck檢測不出錯誤.當你達到這種狀態,你會更容易發現對程序的哪些修改導致Memcheck報告了新的錯誤.數年的Memcheck使用經驗說明,大型程序也能夠使用Memcheck. 比如KDE,Firefox等.

6.更多信息

請查詢 Valgrind FAQ Valgrind User Manual.使用--tool選項可以使用Valgrind中的其他工具.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM