Linux下内存泄露工具
概述
? ? 內(nèi)存泄露(memory leak)指由于疏忽或錯誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況,在大型的、復(fù)雜的應(yīng)用程序中,這時就出現(xiàn)了內(nèi)存泄露。盡管優(yōu)秀的編程實踐可以確保最少的泄露,但是根據(jù)經(jīng)驗,當(dāng)使用大量的函數(shù)對相同的內(nèi)存塊進行處理時,很可能會出現(xiàn)內(nèi)存泄露。
? ??內(nèi)存泄露可以分為以下幾類:
1. 常發(fā)性內(nèi)存泄漏。發(fā)生內(nèi)存泄露的代碼會被多次執(zhí)行到,每次被執(zhí)行的時候都會導(dǎo)致一塊內(nèi)存泄露。
? ? ? ?2. 偶發(fā)性內(nèi)存泄露。發(fā)生內(nèi)存泄漏的代碼只有在某些特定環(huán)境或操作過程下才會發(fā)生。常發(fā)性和偶發(fā)性是相對的。對于特定的環(huán)境,偶發(fā)性的也許就變成了常發(fā)性的。所以測試環(huán)境和測試方法對檢測內(nèi)存泄露至關(guān)重要。
? ? ? ?3.一次性內(nèi)存泄露。發(fā)生內(nèi)存泄露的代碼只會被執(zhí)行一次,或者由于算法上的缺陷,導(dǎo)致總會有一塊且僅一塊內(nèi)存發(fā)生泄露。比如,在一個Singleton類的構(gòu)造函數(shù)中分配內(nèi)存,在析構(gòu)函數(shù)中卻沒有釋放該內(nèi)存。而Singleton類只存在一個實例,所以內(nèi)存泄露只會發(fā)生一次。
? ? ? ?4.隱式內(nèi)存泄露。程序在運行過程中不停地分配內(nèi)存,但是知道結(jié)束的時候才釋放內(nèi)存。嚴格的說這里并沒有發(fā)生內(nèi)存泄露,因為最終程序釋放了所有申請的內(nèi)存,但是對于一個服務(wù)器程序,需要運行幾天,幾周甚至幾個月,不及時釋放內(nèi)存也可能導(dǎo)致耗盡系統(tǒng)的所有內(nèi)存。所以,我們稱這類內(nèi)存泄露為隱式內(nèi)存泄漏。
內(nèi)存泄漏檢測工具
? ??現(xiàn)在有很多方法來檢測內(nèi)存泄露,以下列舉了linux常用的內(nèi)存泄露檢測工具。
? ??1、mtrace
? ? ?應(yīng)用環(huán)境: Linux GLIBC
? ? ?編程語言: C
? ? ?使用方法: 包含頭文件mcheck.h,定義環(huán)境變量MALLOC_TRACE為輸出文件名,程序開始時調(diào)用mtrace()即可。
? ? ?結(jié)果輸出:用戶指定的文件
? ? ?設(shè)計思路:為malloc,realloc,free函數(shù)添加鉤子函數(shù),記錄每一對malloc-free的執(zhí)行
? ? ?優(yōu)缺點:只能檢查使用malloc/realloc/free造成的內(nèi)存泄露
? ? ?如何獲取:GLIBC自帶,可直接使用
? ??
? ? ?2、memwatch
應(yīng)用環(huán)境:Linux
編程語言:C
? ? ? ? 使用方法: 加入memwatch.h,編譯時加上-DMEMWATCH -DMW_STDIO及memwatch.c
? ? ? ?結(jié)果輸出:輸出文件名稱為memwatch.log,在程序執(zhí)行期間,錯誤提示都會顯示在stdout上
? ? ? ?設(shè)計思路:將malloc/realloc/calloc/strdup/free等重定義為mwMalloc(sz, __FILE__, __LINE__)等,內(nèi)部維護一個操作鏈表
? ? ? ? 優(yōu)缺點:能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、內(nèi)存泄露(unfreed memory)、溢出(Overflow)、下溢(underflow)等等
? ? ? ?如何獲取:http://memwatch.sourceforge.net/
? ? ??3、valgrind
? ? ? ?應(yīng)用環(huán)境:Linux
編程語言:C/C++
? ? ? ?使用方法:編譯時加上-g選項,如gcc -g filename.c -o filename,使用如下檢測內(nèi)存使用情況:
? ? ? ?結(jié)果輸出: #valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./filename,就會看到內(nèi)存使用報告
? ? ? ?設(shè)計思路:根據(jù)軟件的內(nèi)存操作維護一個有效地址空間表和無效地址空間表(進程的地址空間)
? ? ? ?優(yōu)缺點:能夠檢測:
- ?使用未初始化的內(nèi)存(Use of uninitialised memory)
- 使用已經(jīng)釋放了的內(nèi)存(Reading/writing memory after it has been free'd)
- 使用超過malloc分配的內(nèi)存空間(Reading/Writing off the end of malloc'd blocks)
- 對堆棧的非法訪問(Reading/writing inappropriate areas on the stack)
- 申請的空間是否有釋放(Memory leaks -- where pointers to malloc'd blocks are lost forever)
- malloc/free/new/delete申請和釋放內(nèi)存的匹配(Mismatched use of malloc/new/new[] vs free/delete/delete[])
- src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions)
- 重復(fù)free
如何獲取:?http://valgrind.org/
? ??4、debug_new
? ? ? ?應(yīng)用環(huán)境:Linux/Windows
編程語言:C++
使用方法: 包含頭文件debug_new.h,鏈接debug_new.cpp
? ? ? ?結(jié)果輸出: 控制臺console
? ? ? ?設(shè)計思路:通過重載new和delete操作符來捕獲內(nèi)存申請/釋放請求,并在程序內(nèi)部維護一個全局靜態(tài)變量的哈希鏈表。在new操作符中,不僅僅分配用戶所要求的的內(nèi)存,而是在為每次分配的內(nèi)存都添加一個頭部,存儲著此次分配的位置信息和鏈表指針,new返回的是分配的這塊內(nèi)存加上頭部偏移后的值,而在之前已經(jīng)將此返回值作了HASH計算并添加到HASH鏈表中了。delete的時候先根據(jù)要釋放的指針地址做HASH計算,然后再遍歷數(shù)組HASH值處的鏈表進行查找,如果找到則將該節(jié)點移除,未找到就abort。這樣在程序結(jié)束之后,通過檢查此數(shù)組中是否還有未釋放的內(nèi)存塊來確定是否有內(nèi)存泄露。
? ? ? ?優(yōu)缺點:跨平臺,僅用于C++程序。
? ? ? ?如何獲取:http://www.ibm.com/developerworks/cn/linux/l-mleak2/index.html
總結(jié)
以上的這些分析工具,所使用的方法大致分為以下幾種:
1、注冊內(nèi)存分配/釋放鉤子函數(shù)(hook)。在Linux下可以malloc_hook,free_hook等5個鉤子函數(shù),在Windows下可以注冊————CrtSetAllocHook鉤子函數(shù),這樣在分配內(nèi)存的時候就可以捕獲這一請求并加以處理。Visual Leak Detecter和mtrace使用此方式。
2、使用宏定義替換。將用戶代碼中的malloc,free替換為宏定義的mwMalloc(sz, __FILE__, __LINE__)等自定義函數(shù),從而跟蹤內(nèi)存情趣,memwatch即使用此方式。
3、操作符重載。此方法僅用于C++語言中,通過重載new、delete操作符來實現(xiàn)跟蹤內(nèi)存請求,重載后的操作符類似于鉤子函數(shù)意義。debug_new采用此方式。
這些工具的輸出方式也分以下幾種:
1、普通環(huán)境下一般輸出到調(diào)試窗口中,很多軟件本身就提供了一個理想的輸出場所,并且GUI應(yīng)用程序輸出到標準輸出時不可見的。Visual Leak Detecter采用此法。
2、輸出到標準輸出或標準錯誤輸出:控制臺應(yīng)用程序可以輸出到屏幕,如memwatch, valgrind, debug_new都是采用這種方法。
3、輸出到日志文件:將結(jié)果輸出到用戶指定或默認的日志文件中,如mtrace和memwatch
?
此外,這些工具的內(nèi)存檢測方式無非也分為兩種:
1、維護一個內(nèi)存操作鏈表,當(dāng)有內(nèi)存申請操作時,將其加入此鏈表中,當(dāng)有釋放操作時,從申請操作從鏈表中移除。如果到程序結(jié)束后此鏈表中還有內(nèi)容,說明有內(nèi)存泄露了;如果要釋放的內(nèi)存操作沒有在鏈表中找到對應(yīng)操作,則說明是釋放了多次。使用此方法的有內(nèi)置的調(diào)試工具,Visual Leak Detecter,mtrace,memwatch,debug_new。
2、模擬進程的地址空間。仿照操作系統(tǒng)對進程內(nèi)存操作的處理,在用戶態(tài)下維護一個地址空間映射,此方法要求對進程地址空間的處理有較深的理解,因為Windows的進程地址空間分布不是開源的,所有模擬起來很困難,因此只支持Linux。采用此方法的是valgrind。
?
總結(jié)
以上是生活随笔為你收集整理的Linux下内存泄露工具的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx-模块内存泄露调试
- 下一篇: Linux下几款C++程序中的内存泄露检