內存泄漏檢測課程設計
❶ 如何檢測C++的內存泄漏,用哪些工具
本文淺談一下C++內存泄漏的檢測,首先我們需要知道程序有沒有內存泄露,然後定位到底是哪行代碼出現內存泄露了,這樣才能將其修復。最簡單的方法當然是藉助於專業的檢測工具,比較有名如BoundsCheck工具,功能非常強大,相信做C++開發的人都離不開它。此外就是不使用任何工具,而是自己來實現對內存泄露的監控,分如下兩種情況:一. 在 MFC 中檢測內存泄漏假如是用MFC的程序的話,很簡單。默認的就有內存泄露檢測的功能。我們用VS2005生成了一個MFC的對話框的程序,發現他可以自動的檢測內存泄露.不用我們做任何特殊的操作. 仔細觀察,發現在每個CPP文件中,都有下面的代碼:#ifdef _DEBUG #define new DEBUG_NEW #endifDEBUG_NEW 這個宏定義在afx.h文件中,就是它幫助我們定位內存泄漏。 在含有以上代碼的cpp文件中分配內存後假如沒有刪除,那麼停止程序的時候,VisualStudio的Output窗口就會顯示如下的信息了:Detected memory leaks! Dumping objects -> d:\code\mfctest\mfctest.cpp(80) : {157} normal block at 0x003AF170, 4 bytes long. Data: < > 00 00 00 00 Object mp complete.在Output窗口雙擊粗體字那一行,那麼IDE就會打開該文件,定位到該行,很容易看出是哪出現了內存泄露。二.檢測純C++的程序內存泄露我試了下用VisualStudio建立的Win32 Console Application和Win32 Project項目,結果都不能檢測出內存泄露。下面一步一步來把程序的內存泄露檢測的機制建立起來。首先,我們需要知道C運行庫的Debug版本提供了許多檢測功能,使得我們更容易的Debug程序。在MSDN中有專門的章節講這個,叫做Debug Routines,建議大家先看看裡面的內容吧。我們會用到裡面很重要的幾個函數。
❷ 檢測出程序內存泄漏,出現下面的提示,請問一下該怎麼解決
雖然說我沒有看到你復的源製程序,但是根據我的編程經驗,你下一步應該檢查一下,在你的源程序中都定義了哪些指針變數?它們是否都成功初始化、並成功分配到了內存?在使用完之後是否進行了成功的釋放內存?因為如果只是一味地使用內存,而在使用完畢之後,又不管釋放內存的話,勢必會造成內存的泄漏。因為內存資源是有限的。另外,就是再檢查一下,是否有其他數組越界的錯誤?例如:以 C 語言為例,雖然定義了一個長度為 100 個元素的整型數組(int num[100] ;),但是在存取該數組的元素時,卻使用到了 100 以外的下標(num[102] = 50 ;)?這些都會造成內存泄漏。
❸ 高分求助!!!C內存泄露檢測問題
你可以對於malloc進行overload,
在malloc中,進行bufferID,Appchain等信息的輸出
❹ 如何檢查內存泄露問題
簡單說明了一下沒有工具的情況如何運用VC庫中的工具來檢查代碼的內存泄漏問題。
一: 內存泄漏
內存泄漏是編程中常常見到的一個問題,內存泄漏往往會一種奇怪的方式來表現出來,基本上每個程序都表現出不同的方式。 但是一般最後的結果只有兩個,一個是程序當掉,一個是系統內存不足。 還有一種就是比較介於中間的結果程序不會當,但是系統的反映時間明顯降低,需要定時的Reboot才會正常。
有 一個很簡單的辦法來檢查一個程序是否有內存泄漏。就是是用Windows的任務管理器(Task Manager)。運行程序,然後在任務管理器裡面查看 「內存使用」和」虛擬內存大小」兩項,當程序請求了它所需要的內存之後,如果虛擬內存還是持續的增長的話,就說明了這個程序有內存泄漏問題。 當然如果內存泄漏的數目非常的小,用這種方法可能要過很長時間才能看的出來。
當然最簡單的辦法大概就是用CompuWare的BoundChecker 之類的工具來檢測了,不過這些工具的價格對於個人來講稍微有點奢侈了。
如果是已經發布的程序,檢查是否有內存泄漏是又費時又費力。所以內存泄漏應該在Code的生成過程就要時刻進行檢查。
二: 原因
內存泄漏產生的原因一般是三種情況:
分配完內存之後忘了回收;
程序Code有問題,造成沒有辦法回收;
某些API函數操作不正確,造成內存泄漏。
1. 內存忘記回收,這個是不應該的事情。但是也是在代碼種很常見的問題。分配內存之後,用完之後,就一定要回收。如果不回收,那就造成了內存的泄漏,造成內存泄漏的Code如果被經常調用的話,那內存泄漏的數目就會越來越多的。從而影響整個系統的運行。比如下面的代碼:
for (int =0;I<100;I++)
{
Temp = new BYTE[100];
}
就會產生 100*100Byte的內存泄漏。
2. 在某些時候,因為代碼上寫的有問題,會導致某些內存想回收都收不回來,比如下面的代碼:
Temp1 = new BYTE[100];
Temp2 = new BYTE[100];
Temp2 = Temp1;
這樣,Temp2的內存地址就丟掉了,而且永遠都找不回了,這個時候Temp2的內存空間想回收都沒有辦法。
3. API函 數應用不當,在Windows提供API函數裡面有一些特殊的API,比如FormatMessage。 如果你給它參數中有FORMAT_MESSAGE_ALLOCATE_BUFFER,它會在函數內部New一塊內存Buffer出來。但是這個 buffer需要你調用LocalFree來釋放。 如果你忘了,那就會產生內存泄漏。
三: 檢查方法
一 般的內存泄漏檢查的確是很困難,但是也不是完全沒有辦法。如果你用VC的庫來寫東西的話,那麼很幸運的是,你已經有了很多檢查內存泄漏的工具,只是你想不 想用的問題了。Visual C++的Debug版本的C運行庫(C Runtime Library)。它已經提供好些函數來幫助你診斷你的代碼和跟蹤內存泄漏。 而且最方便的地方是這些函數在Release版本中完全不起任何作用,這樣就不會影響你的Release版本程序的運行效率。
比如下面的例子裡面,有一個明細的內存泄漏。當然如果只有這么幾行代碼的話,是很容易看出有內存泄漏的。但是想在成千上萬行代碼裡面檢查內存泄漏問題就不是那麼容易了。
char * pstr = new char[5];
lstrcpy(pstr,"Memory leak");
如 果我們在Debug版本的Code裡面對堆(Heap)進行了操作,包括malloc, free, calloc, realloc, new 和 delete可以利用VC Debug運行時庫中堆Debug函數來做堆的完整性和安全性檢查。比如上面的代碼,lstrcpy的操作明顯破壞了pstr的堆結構。使其溢出,並破壞 了臨近的數據。那我們可以在調用lstrcpy之後的代碼裡面加入 _CrtCheckMemory函數。_CrtCheckMemory函數發現前面的lstrcpy使得pstr的堆結構被破壞,會輸出這樣的報告:
emory check error at 0x00372FA5 = 0x79, should be 0xFD.
memory check error at 0x00372FA6 = 0x20, should be 0xFD.
memory check error at 0x00372FA7 = 0x6C, should be 0xFD.
memory check error at 0x00372FA8 = 0x65, should be 0xFD.
DAMAGE: after Normal block (#41) at 0x00372FA0.
Normal located at 0x00372FA0 is 5 bytes long.
它 告訴說 pstr的長度應該時5個Bytes,但是在5Bytes後面的幾個Bytes也被非法改寫了。提醒你產生了越界操作。_CrtCheckMemory 的返回值只有TRUE和FALSE,那麼你可以用_ASSERTE()來報告出錯信息。 上面的語句可以換成 _ASSERTE(_CrtCheckMemory()); 這樣Debug版本的程序在運行的時候就會彈出一個警告對話框,這樣就不用在運行時候一直盯著Output窗口看了。這個時候按Retry,就可以進入源 代碼調試了。看看問題到底出在哪裡。
其他類似的函數還有 _CrtDbgReport, _CrtDoForAllClientObjects, _CrtDumpMemoryLeaks,_CrtIsValidHeapPointer, _CrtIsMemoryBlock, _CrtIsValidPointer,_CrtMemCheckpoint, _CrtMemDifference, _CrtMemDumpAllObjectsSince, _CrtMemDumpStatistics, _CrtSetAllocHook, _CrtSetBreakAlloc, _CrtSetDbgFlag,_CrtSetDumpClient, _CrtSetReportFile, _CrtSetReportHook, _CrtSetReportMode
這 些函數全部都可以用來在Debug版本中檢查內存的使用情況。具體怎麼使用這些函數就不在這里說明了,各位可以去查查MSDN。在這些函數中用處比較大 的,或者說使用率會比較高的函數是_CrtMemCheckpoint, 設置一個內存檢查點。這個函數會取得當前內存的運行狀態。 _CrtMemDifference 檢查兩種內存狀態的異同。 _CrtMemDumpAllObjectsSince 從程序運行開始,或者從某個內存檢查點開始Dump出堆中對象的信息。還有就是_CrtDumpMemoryLeaks當發生內存溢出的時候Dump出堆 中的內存信息。 _CrtDumpMemoryLeaks一般都在有懷疑是內存泄漏的代碼後面調用。比如下面的例子:
#include <windows.h>
#include <crtdbg.h>
void main()
{
char * pstr;
pstr = new char[5];
_CrtDumpMemoryLeaks();
}
輸出:
Detected memory leaks! à提醒你,代碼有內存泄漏.
Dumping objects ->
{44} normal block at 0x00372DB8, 5 bytes long.
Data: < > CD CD CD CD CD
Object mp complete.
如 果你雙擊包含行文件名的輸出行,指針將會跳到源文件中內存被分配地方的行。當無法確定那些代碼產生了內存泄漏的時候,我們就需要進行內存狀態比較。在可疑 的代碼段的前後設置內存檢查點,比較內存使用是否有可疑的變化。以確定內存是否有泄漏。為此要先定義三個_CrtMemState 對象來保存要比較的內存狀態。兩個是用來比較,一個用了保存前面兩個之間的區別。
_CrtMemState Sh1,Sh2,Sh_Diff;
char *pstr1 = new char[100];
_CrtMemCheckPoint(&Sh1); ->設置第一個內存檢查點
char *pstr2 = new char[100];
_CrtMemCheckPoint(&Sh2); ->設置第二個內存檢查點
_CrtMemDifference(&Sh_Diff, &Sh1, &Sh2); ->檢查變化
_CrtMemDumpAllObjectsSince(&Sh_Diff); ->Dump變化
如 果你的程序中使用了MFC類庫,那麼內存泄漏的檢查方法就相當的簡單了。因為Debug版本的MFC本身就提供一部分的內存泄漏檢查。 大部分的new 和delete沒有配對使用而產生的內存泄漏,MFC都會產生報告。這個主要是因為MFC重載了Debug版本的new 和delete操作符, 並且對前面提到的API函數重新進行了包裝。在MFC類庫中檢查內存泄漏的Class就叫 CMemoryState,它重新包裝了了_CrtMemState,_CrtMemCheckPoint, _CrtMemDifference, _CrtMemDumpAllObjectsSince這些函數。並對於其他的函數提供了Afx開頭的函數,供MFC程序使用。比如 AfxCheckMemory, AfxDumpMemoryLeaks 這些函數的基本用法同上面提到的差不多。 CMemoryState和相關的函數的定義都在Afx.h這個頭文件中。 有個簡單的辦法可以跟蹤到這些函數的聲明。在VC中找到MFC程序代碼中下面的代碼, 一般都在X.cpp的開頭部分
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
把 游標移到DEBUG_NEW上面 按F12,就可以進入Afx.h中定義這些Class和函數的代碼部分。 VC中內存泄漏的常規檢查辦法主要是上面的兩種。當然這兩種方法只是針對於Debug版本的Heap的檢查。如果Release版本中還有內存泄漏,那麼 檢查起來就麻煩很多了。
4 .總結:
實際上Heap的內存泄漏問題是相當的好查的。VC的提供的檢查工具也不太少,但是如果是棧出了什麼問題,恐怕就麻煩很多了。棧出問題,一般不會產生內存泄漏,但是你的代碼的邏輯上很有可能會有影響。這個是最最痛苦的事情。 編程,就是小心,小心再小心而已。
❺ C++代碼中的內存泄漏檢查如何做(一)
在含有以上代碼的cpp文件中分配內存後假如沒有進行釋放,那麼停止程序的時候,VisualStudio的Output窗口就會顯示一些提示的信息了,試一下:在裡面加一句 int* p = new int; 然後調試工程,運行結束後你會看到在Output窗口裡輸出了1:Detected memory leaks!2:Dumping objects -3:e:\學習\de\de\de.cpp(20) : {290} normal block at 0x004CD7F8, 4 byteslong.4:Data: < CD CD CD CD5:Object mp complete.6:The program '[11088] de.exe: Native' has exited with code 0 (0x0). 告訴我們在20行有內存泄漏,雙擊這雙就會跳到相應的代碼行,是不是很方便啊! 我試了下用VisualStudio建立的Win32 Console Application和Win32 Project項目,結果都不能檢測出內存泄露。 我們將會使用到裡面很重要的幾個函數。其中最重要的是 _CrtDumpMemoryLeaks使用這個函數,需要包含頭文件crtdbg.h 該函數只在Debug版本才有用,當在調試器下運行程序時,_CrtDumpMemoryLeaks 將在「Output(輸出)」窗口中顯示內存泄漏信息.寫段代碼試驗一下吧,如下: 這個就會在Output窗口輸出如下信息: 雖然輸出了有內存泄漏,但是無法看出是那裡泄漏了,然後下來看看我們的第二個版本的代碼: 它會在Output輸出: 已經很清楚我告訴我們是在17行產生的。 然後我們把代碼修改正確:1:int_tmain(intargc, _TCHAR* argv[])2:{3:int* p =newint;4:deletep;5:_CrtDumpMemoryLeaks();6:return0;7:}運行後,輸出的信息就是正確的了。 所以在寫代碼的時候除了在產生Dump信息外,最重要的就是在程序退出的時候需要掉用一次_CrtDumpMemoryLeaks(); 假如程序有不止一個出口,那麼我們就需要在多個地方都調用該函數。
❻ VC6.0如何啟用內存泄漏檢測機制
VC++ IDE 的默認狀態是沒有啟用內存泄漏檢測機制的,也就是說即使某段代碼有內存泄漏,調試會話的 Output 窗口的 Debug 頁不會輸出有關內存泄漏信息。你必須設定兩個最基本的機關來啟用內存泄漏檢測機制。
一是使用調試堆函數:
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
注意:#include 語句的順序。如果更改此順序,所使用的函數可能無法正確工作。
通過包含 crtdbg.h 頭文件,可以將 malloc 和 free 函數映射到其「調試」版本 _malloc_dbg 和 _free_dbg,這些函數會跟蹤內存分配和釋放。此映射只在調試(Debug)版本(也就是要定義 _DEBUG)中有效。發行版本(Release)使用普通的 malloc 和 free 函數。
#define 語句將 CRT 堆函數的基礎版本映射到對應的「調試」版本。該語句不是必須的,但如果沒有該語句,那麼有關內存泄漏的信息會不全。
二是在需要檢測內存泄漏的地方添加下面這條語句來輸出內存泄漏信息:
_CrtDumpMemoryLeaks();
當在調試器下運行程序時,_CrtDumpMemoryLeaks 將在 Output 窗口的 Debug 頁中顯示內存泄漏信息。比如:
Detected memory leaks!
Dumping objects ->
C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42
c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {44} normal block at 0x00441BD0, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
c:\program files\microsoft visual studio\vc98\include\crtdbg.h(552) : {43} normal block at 0x00441C20, 40 bytes long.
Data: < C > 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00
Object mp complete.
如果不使用 #define _CRTDBG_MAP_ALLOC 語句,內存泄漏的輸出是這樣的:
Detected memory leaks!
Dumping objects ->
{45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42
{44} normal block at 0x00441BD0, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
{43} normal block at 0x00441C20, 40 bytes long.
Data: < C > C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00
Object mp complete.
根據這段輸出信息,你無法知道在哪個源程序文件里發生了內存泄漏。下面我們來研究一下輸出信息的格式。第一行和第二行沒有什麼可說的,從第三行開始:
xx}:花括弧內的數字是內存分配序號,本文例子中是 {45},{44},{43};
block:內存塊的類型,常用的有三種:normal(普通)、client(客戶端)或 CRT(運行時);本文例子中是:normal block;
用十六進制格式表示的內存位置,如:at 0x00441BA0 等;
以位元組為單位表示的內存塊的大小,如:32 bytes long;
前16位元組的內容(也是用十六進制格式表示),如:Data: <AB> 41 42 等;
仔細觀察不難發現,如果定義了 _CRTDBG_MAP_ALLOC ,那麼在內存分配序號前面還會顯示在其中分配泄漏內存的文件名,以及文件名後括弧中的數字表示發生泄漏的代碼行號,比如:
C:\Temp\memleak\memleak.cpp(15)
雙擊 Output 窗口中此文件名所在的輸出行,便可跳到源程序文件分配該內存的代碼行(也可以選中該行,然後按 F4,效果一樣) ,這樣一來我們就很容易定位內存泄漏是在哪裡發生的了,因此,_CRTDBG_MAP_ALLOC 的作用顯而易見。
使用 _CrtSetDbgFlag
如果程序只有一個出口,那麼調用 _CrtDumpMemoryLeaks 的位置是很容易選擇的。但是,如果程序可能會在多個地方退出該怎麼辦呢?在每一個可能的出口處調用 _CrtDumpMemoryLeaks 肯定是不可取的,那麼這時可以在程序開始處包含下面的調用:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
這條語句無論程序在什麼地方退出都會自動調用 _CrtDumpMemoryLeaks。注意:這里必須同時設置兩個位域標志:_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。
設置 CRT 報告模式
默認情況下,_CrtDumpMemoryLeaks 將內存泄漏信息 mp 到 Output 窗口的 Debug 頁, 如果你想將這個輸出定向到別的地方,可以使用 _CrtSetReportMode 進行重置。如果你使用某個庫,它可能將輸出定向到另一位置。此時,只要使用以下語句將輸出位置設回 Output 窗口即可:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
有關使用 _CrtSetReportMode 的詳細信息,請參考 MSDN 庫關於 _CrtSetReportMode 的描述。
解釋內存塊類型
前面已經說過,內存泄漏報告中把每一塊泄漏的內存分為 normal(普通塊)、client(客戶端塊)和 CRT 塊。事實上,需要留心和注意的也就是 normal 和 client,即普通塊和客戶端塊。
normal block(普通塊):這是由你的程序分配的內存。
client block(客戶塊):這是一種特殊類型的內存塊,專門用於 MFC 程序中需要析構函數的對象。MFC new 操作符視具體情況既可以為所創建的對象建立普通塊,也可以為之建立客戶塊。
CRT block(CRT 塊):是由 C RunTime Library 供自己使用而分配的內存塊。由 CRT 庫自己來管理這些內存的分配與釋放,我們一般不會在內存泄漏報告中發現 CRT 內存泄漏,除非程序發生了嚴重的錯誤(例如 CRT 庫崩潰)。
除了上述的類型外,還有下面這兩種類型的內存塊,它們不會出現在內存泄漏報告中。
free block(空閑塊):已經被釋放(free)的內存塊。
Ignore block(忽略塊):這是程序員顯式聲明過不要在內存泄漏報告中出現的內存塊。
如何在內存分配序號處設置斷點?
在內存泄漏報告中,的文件名和行號可告訴分配泄漏的內存的代碼位置,但僅僅依賴這些信息來了解完整的泄漏原因是不夠的。因為一個程序在運行時,一段分配內存的代碼可能會被調用很多次,只要有一次調用後沒有釋放內存就會導致內存泄漏。為了確定是哪些內存沒有被釋放,不僅要知道泄漏的內存是在哪裡分配的,還要知道泄漏產生的條件。這時內存分配序號就顯得特別有用——這個序號就是文件名和行號之後的花括弧里的那個數字。
例如,在本文例子代碼的輸出信息中,「45」是內存分配序號,意思是泄漏的內存是你程序中分配的第四十五個內存塊:
Detected memory leaks!
Dumping objects ->
C:\Temp\memleak\memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
Data: <AB> 41 42
......
Object mp complete.
CRT 庫對程序運行期間分配的所有內存塊進行計數,包括由 CRT 庫自己分配的內存和其它庫(如 MFC)分配的內存。因此,分配序號為 N 的對象即為程序中分配的第 N 個對象,但不一定是代碼分配的第 N 個對象。(大多數情況下並非如此。)
這樣的話,你便可以利用分配序號在分配內存的位置設置一個斷點。方法是在程序起始附近設置一個位置斷點。當程序在該點中斷時,可以從 QuickWatch(快速監視)對話框或 Watch(監視)窗口設置一個內存分配斷點:
例如,在 Watch 窗口中,在 Name 欄鍵入下面的表達式:
_crtBreakAlloc
如果要使用 CRT 庫的多線程 DLL 版本(/MD 選項),那麼必須包含上下文操作符,像這樣:
{,,msvcrtd.dll}_crtBreakAlloc
現在按下回車鍵,調試器將計算該值並把結果放入 Value 欄。如果沒有在內存分配點設置任何斷點,該值將為 –1。
用你想要在其位置中斷的內存分配的分配序號替換 Value 欄中的值。例如輸入 45。這樣就會在分配序號為 45 的地方中斷。
在所感興趣的內存分配處設置斷點後,可以繼續調試。這時,運行程序時一定要小心,要保證內存塊分配的順序不會改變。當程序在指定的內存分配處中斷時,可以查看 Call Stack(調用堆棧)窗口和其它調試器信息以確定分配內存時的情況。如果必要,可以從該點繼續執行程序,以查看對象發生了什麼情況,或許可以確定未正確釋放對象的原因。
盡管通常在調試器中設置內存分配斷點更方便,但如果願意,也可在代碼中設置這些斷點。為了在代碼中設置一個內存分配斷點,可以增加這樣一行(對於第四十五個內存分配):
_crtBreakAlloc = 45;
你還可以使用有相同效果的 _CrtSetBreakAlloc 函數:
_CrtSetBreakAlloc(45);
如何比較內存狀態?
定位內存泄漏的另一個方法就是在關鍵點獲取應用程序內存狀態的快照。CRT 庫提供了一個結構類型 _CrtMemState。你可以用它來存儲內存狀態的快照:
_CrtMemState s1, s2, s3;
若要獲取給定點的內存狀態快照,可以向 _CrtMemCheckpoint 函數傳遞一個 _CrtMemState 結構。該函數用當前內存狀態的快照填充此結構:
_CrtMemCheckpoint( &s1 );
通過向 _CrtMemDumpStatistics 函數傳遞 _CrtMemState 結構,可以在任意地方 mp 該結構的內容:
_CrtMemDumpStatistics( &s1 );
該函數輸出如下格式的 mp 內存分配信息:
0 bytes in 0 Free Blocks.
75 bytes in 3 Normal Blocks.
5037 bytes in 41 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 5308 bytes.
Total allocations: 7559 bytes.
若要確定某段代碼中是否發生了內存泄漏,可以通過獲取該段代碼之前和之後的內存狀態快照,然後使用 _CrtMemDifference 比較這兩個狀態:
_CrtMemCheckpoint( &s1 );// 獲取第一個內存狀態快照
// 在這里進行內存分配
_CrtMemCheckpoint( &s2 );// 獲取第二個內存狀態快照
// 比較兩個內存快照的差異
if ( _CrtMemDifference( &s3, &s1, &s2) )
_CrtMemDumpStatistics( &s3 );// mp 差異結果
顧名思義,_CrtMemDifference 比較兩個內存狀態(前兩個參數),生成這兩個狀態之間差異的結果(第三個參數)。在程序的開始和結尾放置 _CrtMemCheckpoint 調用,並使用 _CrtMemDifference 比較結果,是檢查內存泄漏的另一種方法。如果檢測到泄漏,則可以使用 _CrtMemCheckpoint 調用通過二進制搜索技術來分割程序和定位泄漏。
❼ 內存泄漏檢測原理
先hook系統函數,然後配對檢測。
❽ 如何檢測內存泄漏
首先,我們檢查了代碼,發現所有的代碼都是用new來分配內存,用delete來釋放內存。那麼,我們能夠用一個全程替換,來替換掉所有的new和delete操作符嗎?不能。因為代碼的規模太大了,那樣做除了浪費時間沒有別的任何好處。好在我們的源代碼是用C++來寫成的,所以,這意味著沒有必要替換掉所有的new和delete,而只用重載這兩個操作符。對了,值用重載這兩個操作符,我們就能在分配和釋放內存之前做點什麼。這是一個絕對的好消息。我們也知道該如何去做。因為,MFC也是這么做的。我們需要做的是:跟蹤所有的內存分配和交互引用以及內存釋放。我們的源代碼使用Visual C++寫成,當然這種解決方法也可以很輕松的使用在別的C++代碼裡面。要做的第一件事情是重載new和delete操作符,它們將會在所有的代碼中被使用到。我們在stdafx.h中,加入:
#ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
};
inline void __cdecl operator delete(void *p)
{
};
#endif
這樣,我們就重載了new和delete操作符。我們用$ifdef和#endif來包住這兩個重載操作符,這樣,這兩個操作符就不會在發布版本中出現。看一看這段代碼,會發現,new操作符有三個參數,它們是,分配的內存大小,出現的文件名,和行號。這對於尋找內存泄漏是必需的和重要的。否則,就會需要很多時間去尋找它們出現的確切地方。加入了這段代碼,我們的調用new()的代碼仍然是指向只接受一個參數的new操作符,而不是這個接受三個參數的操作符。另外,我們也不想記錄所有的new操作符的語句去包含__FILE__和__LINE__參數。我們需要做的是自動的讓所有的接受一個參數的new操作符調用接受三個參數的new操作符。這一點可以用一點點小的技巧去做,例如下面的這一段宏定義,
#ifdef _DEBUG
#define DEBUG_NEW new(__FILE__, __LINE__)
#else
#define DEBUG_NEW new
#endif
#define new DEBUG_NEW
現在我們所有的接受一個參數的new操作符都成為了接受三個參數的new操作符號,__FILE__和__LINE__被預編譯器自動的插入到其中了。然後,就是作實際的跟蹤了。我們需要加入一些常式到我們的重載的函數中去,讓它們能夠完成分配內存和釋放內存的工作。這樣來做, #ifdef _DEBUG
inline void * __cdecl operator new(unsigned int size,
const char *file, int line)
{
void *ptr = (void *)malloc(size);
AddTrack((DWORD)ptr, size, file, line);
return(ptr);
};
inline void __cdecl operator delete(void *p)
{
RemoveTrack((DWORD)p);
free(p);
};
#endif
另外,還需要用相同的方法來重載new[]和delete[]操作符。這里就省略掉它們了。
最後,我們需要提供一套函數AddTrack()和RemoveTrack()。我用STL來維護存儲內存分配記錄的連接表。
這兩個函數如下:
typedef struct {
DWORD address;
DWORD size;
char file[64];
DWORD line;
} ALLOC_INFO;
typedef list<ALLOC_INFO*> AllocList;
AllocList *allocList;
void AddTrack(DWORD addr, DWORD asize, const char *fname, DWORD lnum)
{
ALLOC_INFO *info;
if(!allocList) {
allocList = new(AllocList);
}
info = new(ALLOC_INFO);
info->address = addr;
strncpy(info->file, fname, 63);
info->line = lnum;
info->size = asize;
allocList->insert(allocList->begin(), info);
};
void RemoveTrack(DWORD addr)
{
AllocList::iterator i;
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++)
{
if((*i)->address == addr)
{
allocList->remove((*i));
break;
}
}
};
現在,在我們的程序退出之前,allocList存儲了沒有被釋放的內存分配。為了看到它們是什麼和在哪裡被分配的,我們需要列印出allocList中的數據。我使用了Visual C++中的Output窗口來做這件事情。
void DumpUnfreed()
{
AllocList::iterator i;
DWORD totalSize = 0;
char buf[1024];
if(!allocList)
return;
for(i = allocList->begin(); i != allocList->end(); i++) {
sprintf(buf, "%-50s: LINE %d, ADDRESS %d %d unfreed ",
(*i)->file, (*i)->line, (*i)->address, (*i)->size);
OutputDebugString(buf);
totalSize += (*i)->size;
}
sprintf(buf, "----------------------------------------------------------- ");
OutputDebugString(buf);
sprintf(buf, "Total Unfreed: %d bytes ", totalSize);
OutputDebugString(buf);
};
現在我們就有了一個可以重用的代碼,用來監測跟蹤所有的內存泄漏了。這段代碼可以用來加入到所有的項目中去。雖然它不會讓你的程序看起來更好,但是起碼它能夠幫助你檢查錯誤,讓程序更加的穩定。
❾ 關於如何檢測Android的內存泄漏
用leakcanary三方庫,會自動幫你收集,方便查看
在build.gradle中添加依賴
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
在public class App extends Application的專onCreate()方法中:
LeakCanary.install(this);
運行應屬用
具體的位置。特別好用