使用_CrtSetDbgFlag檢測記憶體洩露
介紹:
動態分配、回收記憶體是C/C++程式語言一個最強的特點,但是中國哲學家孫(Sun Tzu,我不知道是誰?那位知道?)指出,最強的同時也是最弱的。這句話對C/C++應用來說非常正確,在記憶體處理出錯的地方通常就是BUGS產生的地方。一個最敏感和難檢測的BUG就是記憶體洩漏-沒有把前邊分配的記憶體成功釋放,一個小的記憶體洩漏可能不需要太注意,但是程式洩漏大塊記憶體,或者漸增式的洩漏記憶體可能引起的現象是:先是效能低下,再就是引起復雜的記憶體耗盡錯誤。最壞的是,一個記憶體洩漏程式可能用完了如此多的記憶體以至於引起其他的程式出錯,留給使用者的是不能知道錯誤到底來自哪裡。另外,一個看上去無害的記憶體洩漏可能是另一個問題的先兆。幸運的是VC++DEBUGER和CRT庫提供了一組有效的檢測和定位記憶體洩漏的工具。本文描述如何使用這些工具有效和系統的排除記憶體洩漏。
_CrtDumpMemoryLeaks()就是檢測從程式開始到執行該函式程序的堆使用情況,通過使用_CrtDumpMemoryLeaks()我們可以進行簡單的記憶體洩露檢測。
啟用記憶體洩露檢測:
檢測記憶體洩漏的主要工具是偵錯程式和 C 執行時庫 (CRT) 除錯堆函式。若要啟用除錯堆函式,請在程式中包括以下語句:
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
注意:
#include必須按照以上所示順序。如果更改了順序,所使用的函式可能無法使用。
通過包括crtdbg.h,將 malloc 和 free 函式對映到其“Debug”版本 _malloc_dbg 和 _free_dbg,這些函式將跟蹤記憶體分配和釋放。此對映只在除錯版本(在其中定義了 _DEBUG
#define語句將 CRT 堆函式的基版本對映到對應的“Debug”版本。並非絕對需要該語句,但如果沒有該語句,記憶體洩漏轉儲包含的有用資訊將較少。
在添加了上面所示語句之後,可以通過在程式中包括以下語句來轉儲記憶體洩漏資訊:
_CrtDumpMemoryLeaks()
使用示範:
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
#definenewnew( _CLIENT_BLOCK, __FILE__, __LINE__)
intmain()
{
int* leak = newint[10];
_CrtDumpMemoryLeaks();
}
這個示範程式與前面講的多了一個巨集定義:
#definenewnew( _CLIENT_BLOCK, __FILE__, __LINE__)
原因稍後再說,我們先看看程式執行(提醒:不要按Ctrl+F5,按F5)後的結果。
程式除錯後在“輸出”視窗輸出如下:
Detected memory leaks!
Dumping objects ->
e:\work\myproject\test\test\test.cpp(57) : {48} client block at 0x00392BB0, subtype 0, 40 bytes long.
Data: <> CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
“輸出”很明顯的告訴了你在test.cpp檔案的第57行分配了一個40位元組的記憶體而沒有釋放。在“輸出”視窗中選擇包含檔名和行號的行,然後按 F4 鍵即可進入到原始檔中分配記憶體的行。
現在我們再來看看如果不加之前那個new的巨集定義會出現怎麼樣的結果。
程式除錯後在“輸出”視窗輸出如下:
Detected memory leaks!
Dumping objects ->
{48} normal block at 0x00392BB0, 40 bytes long.
Data: <> CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
與之前的對比,這次的輸出並沒有告訴我們這個記憶體洩露具體是在哪個位置引起的。另外如果沒定義
#define_CRTDBG_MAP_ALLOC
也會引起同樣的結果。
_CrtSetDbgFlag
如果程式總是在同一位置退出,呼叫 _CrtDumpMemoryLeaks 將非常容易。如果程式從多個位置退出,則無需在每個可能退出的位置放置對 _CrtDumpMemoryLeaks 的呼叫,而可以在程式開始處包含以下呼叫:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
該語句在程式退出時自動呼叫 _CrtDumpMemoryLeaks。必須同時設定 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_ALLOC_MEM_DF 兩個位域,如上所示。
設定 CRT 報告模式
預設情況下,_CrtDumpMemoryLeaks 將記憶體洩漏資訊轉儲到“輸出”視窗的“除錯”窗格,如上所述。可以使用 _CrtSetReportMode 重置該設定,以轉儲到另一位置。如果使用庫,它可以將輸出重置到另一位置。在此情況下,可以使用以下語句將輸出位置設定回“輸出”視窗:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );