寫這篇部落格的原因呢是因為自己在編寫基於Nginx磁碟緩衝管理程式,目前已經進入測試階段,關於這個程式的測試分為幾個主要步驟: 1.記憶體管理是否正確(因為這個程式本身開闢很多記憶體空間進行緩衝管理,同時這個程式程式本身就是基於C/C++開發的,記憶體管理機制一直是程式員頭痛的東西) 2.程式的健碩性如何(伺服器任何程式的基本要求就是要滿足高並發的要求,也就是說,如果達不到這個基本要求,程式並並不能成為伺服器) 針對第一點,以下將介紹幾款記憶體流失檢查工具
| 工具 |
描述 |
| valgrind |
一個強大開源的程式偵查工具 |
| mtrace |
GNU擴充,用來跟蹤malloc,mtrace為記憶體配置函數(malloc,rellaoc,memalign,free)安裝hook函數 |
| dmalloc |
用於檢查C/C++記憶體流失的工具,即是檢查是否存在程式運行結束還沒有釋放的記憶體,以一個運行庫發布 |
| memwatch |
和dmalloc一樣,它能檢測未釋放的記憶體、同一段記憶體被釋放多次、位址存取錯誤及不當使用未分配之記憶體地區 |
| mpatrol |
一個跨平台的 C++ 記憶體流失檢測器 |
| dbgmem |
也是一個動態庫發布的形式,優點類似dmalloc,但是相比之下,可能特點少了一些 |
| Electric Fence |
不僅僅能夠跟蹤malloc()和free(),同時能夠檢查讀訪問以及寫入,能夠準確指出導致錯誤的指令 |
Valgrind詳解
Valgrind包括以下一些工具: 1.Memcheck:這是valgrind應用最廣泛的工具,一個重量級的記憶體檢查器,能夠給發現開發中絕大多數的記憶體錯誤使用的情況,比如:使用未初始化 2.callgrind:它主要用來檢查程式中函數中調用過程中出現的問題 3.cachegrind:它主要用來檢查程式中緩衝使用出現的問題 4.Helgrind:它主要用來檢查多線程中出現的競爭問題 5.Massif:它主要用來檢查程式中堆棧使用中出現的問題 6.Extension:可以使用core提供的 功能,自己編寫特定的記憶體調試 工具 Linux程式記憶體空間布局
程式碼片段(.text):這裡存放的是CPU要執行的指令,代碼是可共用的,相同的代碼在記憶體中只有一份拷貝,同時這個段是唯讀,防止程式由於錯誤而修改自身指令 初始化資料區段(.data)。這裡存放的是程式中需要明確賦初始值的變數,例如位於所有函數之外的全域變數:int val=100。需要強調的是,以上兩段都是位於程式的可執行檔中,核心在調用exec函數啟動該程式時從來源程式檔案中讀入。 未初始化資料區段(.bss)。位於這一段中的資料,核心在執行該程式前,將其初始化為0或者null。例如出現在任何函數之外的全域變數:int sum;以及未初始化或初值為0的全域變數和靜態局部變數 堆(Heap)。這個段用於在程式中進行動態記憶體申請,例如經常用到的malloc,new系列函數就是從這個段中申請記憶體。
已初始化且初值非0的全域變數和靜態局部變數 棧(Stack)。函數中的局部變數以及在函數調用過程中產生的臨時變數都儲存在此段中。可執行代碼、字串字面值、唯讀變數。 記憶體檢查原理
Memcheck檢測記憶體問題的原理圖:
1.Valid-value表:
對於進程的整個地址空間中的每一位元組(byte),都有與之對應的8個bits,對於CPU的每個寄存器,也有一個與之對應的bit向量。這些bits負責記錄該位元組或者寄存器值是否具有有效 的、已經初始化的值 2.Valid-Address表
對於進程整個地址空間中的 麼一個位元組(byte),還有與 之對應的1bit,負責記錄該地址是否能夠被讀寫。 檢測原理 當要讀寫記憶體中的某個位元組時,首先檢查這個位元組對應的A bit。如果該A bit顯示該位置是無效位置,memcheck則報告讀寫錯誤。 核心(core)類似於 一個虛擬CPU的環境,這樣當記憶體中的某個位元組被載入到真實的CPU中時,該位元組對應的V bit也被載入到虛擬CPU環境中,一旦寄存器中的值,被用來產生記憶體位址,或者該值能夠影響程式 的輸出,則memcheck會檢查對應的vbits,如果該值尚未初始化,則會報告使用未初始化記憶體錯誤。
接下來我主要是介紹valgrind的安裝和使用,關於其他的工具,大家可以自己上網去查閱資料,謝謝配合。 Valgrind 安裝 1.解壓安裝包
tar -jxvf valgrind-3.11.0.tar.bz2 -C /usr/local/src
2.進入目錄安裝
cd /usr/local/src/valgrind-3.11.0
3.運行./autogen.sh 設定環境(需要標準的autoconf工具)
./autogen.sh
4.配置Valgrind,產生MakeFile檔案
./configure --prefix=/usr/local
5.編譯和安裝valgrind
make && make install
valgrind 使用
第一步:準備好程式
為了valgrind發現的錯誤更精確,如能夠定位到原始碼的行,建議在編譯時間加上-g參數,編譯最佳化選項選擇O0(不要最佳化)
第二步:在valgrind下,運行可執行程式
利用valgrind調試記憶體問題,不需要重新編譯來源程式,它的輸入就是二進位的可執行程式。調用Valgrind的通用格式是:valgrind [valgrind-options] your-prog [your-prog-options]
Valgrind 的參數分為兩類,一類是 core 的參數,它對所有的工具都適用;另外一類就是具體某個工具如 memcheck 的參數。Valgrind 預設的工具就是 memcheck,也可以通過“–tool=tool name”指定其他的工具。Valgrind 提供了大量的參數滿足你特定的調試需求,具體可參考其使用者手冊。
利用Memcheck發現常見的記憶體問題總結
Memcheck將記憶體泄露分為兩種,一種是可能的記憶體泄露(Possibly lost),另外一種是確定的記憶體泄露(Definitely lost)。Possibly lost 是指仍然存在某個指標能夠訪問某塊記憶體,但該指標指向的已經不是該記憶體首地址。Definitely lost 是指已經不能夠訪問這塊記憶體。而Definitely lost又分為兩種:直接的(direct)和間接的(indirect)。直接和間接的區別就是,直接是沒有任何指標指向該記憶體,間接是指指向該記憶體的指標都位於記憶體泄露處。在上述的例子中,根節點是directly lost,而其他節點是indirectly lost