一. 在 MFC 中檢測內存泄漏
假如是用MFC的程序的話,很簡單。默認的就有內存泄露檢測的功能。
我們用VS2005生成了一個MFC的對話框的程序,發現他可以自動的檢測內存泄露.不用我們做任何特殊的操作. 仔細觀察,發現在每個CPP文件中,都有下面的代碼:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
DEBUG_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 dump complete.
在Output窗口雙擊粗體字那一行,那么IDE就會打開該文件,定位到該行,很容易看出是哪出現了內存泄露。
顯示信息的解釋:
{xx}:花括弧內的數字是內存分配序號,本文例子中是 {157}
block:內存塊的類型,常用的有三種:normal(普通)、client(客戶端)或 CRT(運行時);本文例子中是:normal block;
用十六進制格式表示的內存位置,如:at 0x003AF170 等;
以字節為單位表示的內存塊的大小,如:4 bytes long;
前 16 字節的內容(也是用十六進制格式表示),如:Data: 00 00 00 00等;
二.檢測純C++的程序內存泄露
使用
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
例:
三.找到內存泄露的調用語句
_CrtSetBreakAlloc(xxx); //其中參數是{}中出現的數值,表示第幾次分配內存
盡量放到程序的前面
具體的調試方法:
1.程序運行到
if (_crtBreakAlloc != -1L && lRequest == _crtBreakAlloc)
_CrtDbgBreak();
就會設置斷點
2. 點擊break
3.一直用debug中的step out(shift+F11)就可以找到調用點
四、如何比較內存狀態
定位內存泄漏的另一個方法就是在關鍵點獲取應用程序內存狀態的快照。CRT 庫提供了一個結構類型 _CrtMemState。你可以用它來存儲內存狀態的快照:
_CrtMemState s1, s2, s3;
若要獲取給定點的內存狀態快照,可以向 _CrtMemCheckpoint 函數傳遞一個 _CrtMemState 結構。該函數用當前內存狀態的快照填充此結構:
_CrtMemCheckpoint( &s1 );
通過向 _CrtMemDumpStatistics 函數傳遞 _CrtMemState 結構,可以在任意地方 dump 該結構的內容:
_CrtMemDumpStatistics( &s1 );
該函數輸出如下格式的 dump 內存分配信息:
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 );// dump 差異結果
顧名思義,_CrtMemDifference 比較兩個內存狀態(前兩個參數),生成這兩個狀態之間差異的結果(第三個參數)。在程序的開始和結尾放置 _CrtMemCheckpoint 調用,並使用 _CrtMemDifference 比較結果,是檢查內存泄漏的另一種方法。如果檢測到泄漏,則可以使用 _CrtMemCheckpoint 調用通過二進制搜索技術來分割程序和定位泄漏。
內存塊類型:
內存泄漏報告中把每一塊泄漏的內存分為 normal(普通塊)、client(客戶端塊)和 CRT 塊。事實上,需要留心和注意的也就是 normal 和 client,即普通塊和客戶端塊。
1.normal block(普通塊):這是由你的程序分配的內存。
2.client block(客戶塊):這是一種特殊類型的內存塊,專門用於 MFC 程序中需要析構函數的對象。MFC new 操作符視具體情況既可以為所創建的對象建立普通塊,也可以為之建立客戶塊。
3.CRT block(CRT 塊):是由 C RunTime Library 供自己使用而分配的內存塊。由 CRT 庫自己來管理這些內存的分配與釋放,我們一般不會在內存泄漏報告中發現 CRT 內存泄漏,除非程序發生了嚴重的錯誤(例如 CRT 庫崩潰)。
除了上述的類型外,還有下面這兩種類型的內存塊,它們不會出現在內存泄漏報告中:
1.free block(空閑塊):已經被釋放(free)的內存塊。
2.Ignore block(忽略塊):這是程序員顯式聲明過不要在內存泄漏報告中出現的內存塊。