記憶體洩漏是指程式在運作過程中,申請了記憶體空間但沒有及時釋放,導致記憶體佔用越來越多,甚至造成系統崩潰的現象。記憶體洩漏是常見的軟體缺陷,對於 Linux 系統來說,也是一個不容忽視的問題。那麼,如何在 Linux 下發現和修復記憶體洩漏呢?有哪些工具可以幫助我們進行記憶體洩漏的偵測和分析呢?本文將為你介紹 Linux 下的幾種常用的記憶體洩漏工具,讓你在 Linux 下更好地管理和優化記憶體資源。
#記憶體外洩可以分為以下幾類:
1.常性內存洩漏。發生記憶體洩漏的程式碼會被執行多次,每次執行的時候都會導致一塊記憶體洩漏。
2.偶發性記憶體洩漏。發生記憶體洩漏的程式碼只有在某些特定環境或操作過程下才會發生。常發性和偶發性是相對的。對於特定的環境,偶發性的也許就變成了常性的。所以測試環境和測試方法對檢測記憶體洩漏至關重要。
3.一次性內存洩漏。發生記憶體洩漏的程式碼只會執行一次,或者由於演算法上的缺陷,導致總會有一塊且僅一塊記憶體發生洩漏。例如,在一個Singleton類別的建構函式中分配內存,在析構函式中卻沒有釋放該記憶體。而Singleton類別只存在一個實例,所以記憶體洩漏只會發生一次。
4.隱式記憶體洩漏。程式在運行過程中不停的分配內存,但是直到結束的時候才釋放內存。嚴格的說這裡並沒有發生記憶體洩漏,因為最終程序釋放了所有申請的記憶體。但是對於一個伺服器程序,需要運行幾天,幾週甚至幾個月,不及時釋放記憶體也可能導致最終耗盡系統的所有記憶體。所以,我們稱這類記憶體洩漏為隱式記憶體洩漏。
#現在有很多方法來偵測記憶體洩露,以下列舉了linux常用的記憶體外洩偵測工具。
#應用環境:Linux GLIBC
程式語言:C
使用方法: 包含頭檔mcheck.h,定義環境變數MALLOC_TRACE為輸出檔名,程式開始時呼叫mtrace()即可。
結果輸出:使用者指定的檔案
設計思路: 為malloc,realloc,free函數加入鉤子函數,記錄每一對malloc-free的執行
優缺點:只能檢查使用malloc/realloc/free造成的記憶體外洩
#如何取得:GLIBC自帶,可直接使用
#應用程式環境:Linux
程式語言:C
使用方法: 加入memwatch.h,編譯時加上-DMEMWATCH -DMW_STDIO及memwatch.c
結果輸出:輸出檔案名稱為memwatch.log,在程式執行期間,錯誤提示都會顯示在stdout上
設計想法:將malloc/realloc/calloc/strdup/free等重新定義為mwMalloc(sz, FILE, LINE)等,內部維護一個操作鍊錶
優缺點:能偵測雙重釋放(double-free)、錯誤釋放(erroneous free)、記憶體洩漏(unfreed memory)、溢位(Overflow)、下溢(Underflow)等等
如何取得:http://memwatch.sourceforge.net/
#應用程式環境:Linux
程式語言:C/C
使用方法: 編譯時加上-g選項,如 gcc -g filename.c -o filename, 使用以下指令偵測記憶體使用:
結果輸出:#valgrind –tool=memcheck –leak-check=yes –show-reachable=yes ./filename,就會看到記憶體使用報表
設計想法:根據軟體的記憶體操作維護一個有效位址空間表和無效位址空間表(進程的位址空間)
優缺點:能夠偵測:
如何取得:http://valgrind.org/
應用程式環境:Linux/Windows
程式語言:C
使用方法: 包含頭檔debug_new.h,連結debug_new.cpp
結果輸出:控制台console
設計想法: 透過重載new和delete運算子來擷取記憶體申請/釋放請求,並在程式內部維護一個全域靜態變數的雜湊鍊錶。在new操作符中,不僅分配用戶所要求的內存,而是在為每次分配的內存都添加一個頭部,存儲著此次分配的位置信息和鍊錶指針,new返回的是分配的這塊記憶體加上頭部偏移後的值,而在先前已經將此傳回值作了HASH計算並加入到HASH鍊錶中了。 delete的時候先依照要釋放的指標位址做HASH計算,然後再遍歷數組HASH值處的鍊錶進行查找,如果找到則將該節點移除,未找到就abort。這樣在程式結束之後,透過檢查此數組中是否還有未釋放的記憶體區塊來確定是否有記憶體洩漏。
優缺點:跨平台,僅用於C 程序,
如何取得:http://www.ibm.com/developerworks/cn/linux/l-mleak2/index.html
以上的這些分析工具,所使用的方法大致分為以下幾種:
1、註冊記憶體分配/釋放鉤子函數(hook)。在Linux下可以malloc_hook, free_hook等5個鉤子函數,在Windows下可以註冊_CrtSetAllocHook鉤子函數,這樣在分配記憶體的時候就可以捕獲這一請求並加以處理。 Visual Leak Detecter和mtrace使用此方式。
2、使用巨集定義替換。將使用者程式碼中的malloc, free 替換為巨集定義的 mwMalloc(sz, FILE, LINE)等自訂函數,從而追蹤記憶體請求,memwatch即使用此方式。
3、運算子重載。此方法僅用於C 語言中,透過重載new、delete操作符來實現追蹤記憶體請求,重載後的操作符類似於鉤子函數意義。 debug_new採用此方式。
這些工具的輸出方式也分成以下幾種:
1、普通環境下一般輸出到調試視窗中,許多軟體本身就提供了一個理想的輸出場所,並且GUI應用程式輸出到標準輸出時不可見的。 Visual Leak Detecter採用此法。
2、輸出到標準輸出或標準錯誤輸出:控制台應用程式可以輸出到螢幕,如memwatch, valgrind, debug_new都是採用這種方法。
3、輸出到日誌檔案:將結果輸出到使用者指定或預設的日誌檔案中,例如mtrace和memwatch。
此外,這些工具的記憶體偵測方式無非也分為兩種:
1、維護一個記憶體操作鍊錶,當有記憶體申請作業時,將其加入此鍊錶中,當有釋放作業時,從申請作業從鍊錶移除。如果到程式結束後此鍊錶還有內容,表示有記憶體洩漏了;如果要釋放的記憶體操作沒有在鍊錶中找到對應操作,則表示是釋放了多次。使用此方法的有內建的偵錯工具,Visual Leak Detecter,mtrace, memwatch, debug_new。
2、模擬行程的位址空間。仿照作業系統對進程記憶體操作的處理,在使用者態下維護一個位址空間映射,此方法要求對進程位址空間的處理有較深的理解。因為Windows的進程位址空間分佈不是開源的,所以模擬起來很困難,因此只支援Linux。採用此方法的是valgrind。
透過本文,你應該對 Linux 下的記憶體洩漏問題有了基本的認識,知道了它的原因、影響和解決方法。你也了解了 Linux 下的幾種常用的記憶體洩漏工具,如 Valgrind、Memwatch、Mtrace 等,以及它們的使用方法和優缺點。我們建議你在開發和測試 Linux 程式時,使用這些工具來偵測和分析記憶體洩漏問題,從而提高程式的效能和穩定性。同時,我們也提醒你在使用這些工具時要注意一些注意事項和限制條件,以免造成誤判或遺漏。希望這篇文章能幫助你更好地使用 Linux 系統,讓你在 Linux 下寫出高品質的程式。
以上是Linux 下如何偵測並解決記憶體洩漏問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!