使用 DrMemory 詳細教程

Dr Memory 簡介

Dr. Memory 是一個開源免費的內存檢測工具,它可以及時發現內存相關的編程錯誤,好比未初始化訪問、內存非法訪問以及內存泄露等。它不只可以在 Linux 下面工做,也能在微軟的 Windows 操做系統上工做。不過,本文撰寫時,DrMemory 僅能支持 32 位程序,這是它的一個巨大缺陷,但相信隨着開發的進行,DrMemory 會推出支持 64 位程序的版本。html

Dr Memory 與 Valgrind 相似,能夠直接檢查已經編譯好的可執行文件。用戶不用改寫被檢查程序的源代碼,也無須從新連接第三方庫文件,使用起來很是方便。ios

Dr. Memory 創建在 DynamoRIO 這個動態二進制插樁平臺上。動態監測程序的運行,並對內存訪問相關的執行代碼進行動態修改,記錄其行爲,並採用先進的算法進行錯誤檢查。算法

根據 DrMemory 開發人員發表在 CGO 2011上的論文 Practical Memory Checking with Dr. Memory,DrMemory 對程序的正常執行影響較小,這在同類工具中是比較領先的。其 performance 和 Valgrind 的比較如圖 1 所示(圖片源自 DrMemory 主頁):編程

圖 1. 和 Valgrind 的性能比較

 

Valgrind 對程序的正常運行影響較大,通常來講若是進行全面內存檢測,會使程序的運行速度有 50 到 300 倍的減慢。而 DrMemory 在這個方面則有必定的優點。數組

易用性和性能是 DrMemory 的主要優勢,此外 DrMemory 能夠用於調試 Windows 程序,所以它被普遍認爲是 Windows 上的 Valgrind 替代工具。在 Linux 平臺中,DrMemory 也每每能夠做爲 Valgrind 以外的另外一個選擇。數據結構

DrMemory 對內存泄露的監測採用了比較獨特的算法,大量減小了」false positive」,即虛假錯誤。若是您使用 Valgrind 等工具後仍沒法找到程序中的內存錯誤,不妨試試 DrMemory 吧。函數

在 Linux 上,DrMemory 的目前版本尚不能調試 64 位程序,這是它的一個比較大的缺點。工具

DrMemory 的安裝

在 Linux 上,安裝 Dr Memory 很是簡單,簡單地將下載包解壓便可,如性能

tar –xzvf DrMemory-Linux-1.4.6-2.tar.gz

要想使用 DrMemory,要保證下面這些軟件已經正確安裝:學習

perl、objdump、addr2line。

在任何一個當前的 Linux 發行版中,這幾個軟件應該都已經安裝了,所以基本上您只須要下載 DrMemory 的 tar 包,而後解壓便可使用了。

Windows 上 DrMemory 提供了可執行安裝包,只需點擊下一步,便可安裝完畢。

Hello DrMemory,第一印象

DrMemory 的使用很簡單,能夠說它是傻瓜式。首先個人DrMemory安裝路徑是C:\Program Files (x86)\Dr. Memory\bin64\drmemory.exe;示例程序可執行文件路徑:C:\Users\31937\Desktop\test\bin\Debug\test.exe,而後在執行drmemory.exe  C:\Users\31937\Desktop\test\bin\Debug\test.exe命令時,先須要將控制檯路徑切換到你的DrMemory安裝路徑下,而後執行drmemory.exe  C:\Users\31937\Desktop\test\bin\Debug\test.exe命令

C:\Program Files (x86)\Dr. Memory\bin64>drmemory.exe  C:\Users\31937\Desktop\test\bin\Debug\test.exe

示例程序1:

1 #include <stdlib.h>
2 using namespace std;
3 
4 int main()
5 {
6     int *pPtr = (int *)malloc(sizeof(int));
7     return 0;
8 }

 

執行完命令後控制檯顯示的結果爲:

屏幕上會有如上所示的錯誤彙總,4 byte(s) of leak(s) 而且將定位在main.cpp的第6行。不錯吧。根據提示,更多的細節被寫入一個 result 文本文件。打開並查看該文件,就能夠知道程序在哪裏出現了內存錯誤了。真是太方便了。不過 result 文件是否容易閱讀呢?下面咱們來詳細解釋如何閱讀 DrMemory 產生的 result 文件。

1、DrMemory 錯誤報告類型

DrMemory總共能夠檢測出4種主要錯誤他們分別是內存非法訪問(Unaddressable Access)、未初始化讀(Uninitialized Access)、Heap 操做參數錯誤(Invalid Heap Argument) 、內存泄漏(Memory Leaks),下面對這幾種主要錯誤來進行詳細講解:

1)內存非法訪問(Unaddressable Access)

DrMemory 認爲任何對未分配內存區域的讀寫都是非法的。

非法訪問就是對以上三種方法分配的內存區域以外進行的訪問。常見的問題包括 buffer overflow、數組越界、讀寫已經 free 的內存、堆棧溢出等等。讓咱們測試下面這個問題程序。

例子程序2:

 1 #include <iostream>
 2 #include <stdlib.h>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     char *x = (char *)malloc(sizeof(char));
 8     char c = *(x+8);   //buffer overlow
11     return 0;
12 }

Buffer overflow

例子程序的第8 行存在 buffer overflow。在內存中,buffer 的分佈以下圖所示:

圖 2. Buffer 分佈

 

訪問 x+8 將產生一個非法內存訪問。對此,Dr Memory 將給出以下的錯誤信息:

 首先用大寫的單詞 UNADDRESSABLE ACCESS 代表這是一個非法訪問錯誤。接着,「reading 0x01397620-0x01397621 1 byte(s)」表示這是一個非法讀,讀取的範圍爲 0x01397620到 0x01397621,一共讀了 1 個 byte。接下來的三行是調用堆棧信息,能夠方便地看到錯誤發生在哪一個源文件的哪一行(程序 t 須要在用 gcc 編譯的時候給定-g 選項)。此外 DrMemory 還給出了一些輔助的錯誤信息。好比:

1.錯誤發生的位置:# 0 main               [C:/Users/31937/Desktop/test/main.cpp:8]

2.錯誤發生的時間:Note: @0:00:00.516 in thread 9716。這代表錯誤是程序開始的第 0.516 秒後發生的,有些狀況下,人們能夠根據這個時間進行輔助判斷。

3.錯誤細節:Note: refers to 7 byte(s) beyond last valid byte in prior malloc。這裏給出了錯誤的詳細信息,如前所述,形成非法訪問的可能不少,在本例中是 buffer overflow,所以這裏的詳細信息能夠幫助咱們瞭解非法訪問的具體緣由。

Note: prev lower malloc:  0x01397618-0x01397619。這裏給出了 overflow 以前的合法內存地址,有些狀況下對於查錯 有必定的幫助。

Note: instruction: mov    0x08(%eax) -> %al。這裏給出的是形成錯誤的具體指令。

2)未初始化讀(Uninitialized Access)

讀取未初始化的內存其結果是未知的,使用這樣的數據是很危險的。讓咱們查看下面這個測試程序(並不危險的程序):

示例程序3:

 1 #include <iostream>
 2 #include <stdlib.h>
 3 using namespace std;
 4 
 5 class Test
 6 {
 7     public:int m_iNum;
 8 };
 9 int main()
10 {
11     Test pTest;
12     cout<<pTest.m_iNum;
13     return 0;
14 }

運行結果:

首先用大寫的單詞 UNINITIALIZED READ 代表這是一個未初始化讀錯誤。這是常見的類成員變量沒有進行初始化錯誤

3)Heap 操做參數錯誤(Invalid Heap Argument)

C 語言用 malloc()、free()等函數處理內存 heap 的使用。若是使用不當,會形成未知後果,好比傳入 free()的參數不正確,可能形成 crash,或者用 new 分配,卻用 free 來釋放內存。這類錯誤 DrMemory 稱之爲 Invalid Heap Argument 錯誤。

示例程序4:

 1 #include <iostream>
 2 #include <stdlib.h>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     int *pPtr = (int *)malloc(sizeof(int));
 8     free(pPtr);
 9     free(pPtr);
10     return 0;
11 }

運行結果

首先用大寫的單詞 INVALID HEAP ARGUMENT 代表這是一個Heap 操做參數錯誤。

4)內存泄漏(Memory Leaks) 

內存泄露是常見的內存錯誤,咱們可能都曾經遇到過。不過 Dr.Memory 對內存泄露的定義比較獨特,在程序退出以前,Dr.Memory 把全部依然被分配的內存分爲三類:

Still-reachable allocation

不少程序分配了內存以後,在其整個生命週期內都不釋放。雖然這是一種泄露,但實際上多數狀況下這是無害的,甚至是特地這樣設計的。所以 Dr.Memory 並不認爲這是一種內存泄露,而稱之爲」Still-reachable allocation」。

Leak

有一些內存沒法再被釋放,由於指向該內存的指針丟失了。好比下面這個代碼:

內存 Leak 例子代碼
1 char *ptr = (char *)malloc(sizeof(char)*10);
2 char *ptr1 = (char *)malloc(sizeof(char)*100);

3 ptr=ptr1; //leak

DrMemory 稱這類錯誤爲內存泄露。由於這些內存已經沒有辦法被釋放了。

Possible Leak

如前所述指向內存的指針被修改會被認爲是一個 Leak,但並不是全部的指針修改都是一個 Leak。DrMemory 利用一些經驗規則(Heuristic)將如下幾種指針修改列爲 Possible Leak。

第一種狀況:C++程序利用 new[]分配了一個數組,該數組的每一個元素都是 擁有本身的析構函數的複雜數據結構。這種狀況下,New 操做符爲每一個元素加上一個 header 用來保存數組的個數,以便 delete[]操做符知道須要調用多少個析構函數。但 new[]返回 caller 的是 header 以後的地址,這樣就變成了一個 mid-allocation 指針。這可能被 Dr memory 認爲是一個內存泄露。但可使用-no_midchunk_new_ok 選項讓 DrMemory 將這類錯誤報告爲」possible leak」而非」leak」。

參考下圖,理解這種狀況。

圖 4.mid-chunk new

從堆分配器的角度來看,buffer 的起點在 A 處,但 new 返回 B,給 Object 變量賦值。從某種角度上看,指針 A 丟失了,是一個 leak,但實際上,當調用 delete []操做符時,C++運行時庫會自動將 Object 指針減 4,從而指向 A 點,再進行釋放。某些編譯器不使用這種作法,則沒有這個問題。

第二種狀況,某些 C++編譯器在處理多繼承時,會出現 mid-chunk 指針。很抱歉,具體細節本人也不甚瞭解。Dr Memory 的原文以下:it includes instances of a pointer to a class with multiple inheritance that is cast to one of the parents: it can end up pointing to the subobject representation in the middle of the allocation. 您能夠用-no_midchunk_inheritance_ok 選項將這類「錯誤」報告爲」possible leak」 。

還有一種可能:std::string 類把一個 char[]數組放置在分配空間中,並返回一個指針直接指向它,形成了一個 mid-allocation 指針。您能夠用-no_midchunk_string_ok 選項讓這類錯誤顯示爲」possible leak」。

示例程序5:

1 #include <stdlib.h>
2 using namespace std; 3 4 int main() 5 { 6 int *pPtr = (int *)malloc(sizeof(int)); 7 return 0; 8 }

 

顯示的結果:

屏幕上會有如上所示的錯誤彙總,4 byte(s) of leak(s) 而且將定位在main.cpp的第6行。不錯吧。根據提示,更多的細節被寫入一個 result 文本文件。打開並查看該文件,就能夠知道程序在哪裏出現了內存錯誤了。真是太方便了。不過 result 文件是否容易閱讀呢?下面咱們來詳細解釋如何閱讀 DrMemory 產生的 result 文件。

結束語

很高興也很遺憾我能爲你們介紹一款新的內存調試工具。咱們恐怕已經面臨太多的選擇,假如您用 Google 搜索,會找到不少相似的工具,他們中的多數都不易使用,也許您花了不少的精力去學習某款工具的使用,卻發現它根本就不適合您的環境。

惋惜,不一樣的工具備不一樣的優勢和缺點,直到今天,尚沒有一款工具可以替代全部其它的同類。寫程序有時很無奈,尤爲是面對內存錯誤的時候,多一個選擇也許會讓你擺脫困境。下一次,假如人們告訴您程序有內存泄露,那麼不妨用 DrMemory 試一下。

相關文章
相關標籤/搜索