使用vs的記憶體檢測有以下幾種方法。
在debug模式下以F5運行:
方法一:
#define CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> //在入口函數中包含 _CrtDumpMemoryLeaks(); //即可檢測到記憶體泄露//以如下測試函數為例:int main(){char* pChars = new char[10];_CrtDumpMemoryLeaks();return 0;}
F5運行輸出視窗會得到:
Detected memory leaks!
Dumping objects ->
{58} normal block at 0x00341A38, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.
以上方法沒有輸出
注意:
1.在VS2010下測試的時候,發現_CrtDumpMemoryLeaks();這句必須放在函數結束處,放在主函數入口處輸出視窗不會輸出記憶體泄露資訊
2.{}中的數字指明這塊記憶體是程式中總計第幾個被申請的,這種方法沒有行號和其他資訊輸出。我們可以定義:
#ifdef _DEBUG#define New new(_NORMAL_BLOCK, __FILE__, __LINE__)#endif#define CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> //在入口函數中包含 _CrtDumpMemoryLeaks(); //即可檢測到記憶體泄露//以如下測試函數為例:int main(){char* pChars = New char[10];_CrtDumpMemoryLeaks();return 0;}
輸出:
Detected memory leaks!
Dumping objects ->
e:\vs2005\stltest\stltest\test.cpp(14) : {58} normal block at 0x00591A38, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.
方法二:
#define CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> //在入口函數中包含 _CrtDumpMemoryLeaks(); //即可檢測到記憶體泄露//定義函數:inline void EnableMemLeakCheck(){_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);}//該函數可以放在主函數的任意位置,都能正確的觸發記憶體泄露輸出//以如下測試函數為例:int main(){EnableMemLeakCheck();char* pChars = new char[10];//_CrtDumpMemoryLeaks();return 0;}
輸出:
Detected memory leaks!
Dumping objects ->
{58} normal block at 0x004F1A38, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.
方法三:直接定位指定記憶體塊錯誤的程式碼
單確定了記憶體流失發生在哪一行,有時候並不足夠。特別是同一個new對應有多處釋放的情形。在實際的工程中,以下兩種情況很典型:
建立對象的地方是一個類工廠(ClassFactory)模式。很多甚至全部類執行個體由同一個new建立。對於此,定位到了new出對象的所在行基本沒有多大協助。
COM對象。我們知道COM對象採用Reference Count維護生命週期。也就是說,對象new的地方只有一個,但是Release的地方很多,你要一個個排除。
那麼,有什麼好辦法,可以迅速定位記憶體流失?
答:有。
在記憶體流失情況複雜的時候,你可以用以下方法定位記憶體流失。這是我個人認為通用的記憶體流失追蹤方法中最有效手段。
我們再回頭看看crtdbg產生的記憶體流失報告:
Detected memory leaks!
Dumping objects ->
{58} normal block at 0x004F1A38, 10 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD
Object dump complete.
除了產生該記憶體流失的記憶體配置語句所在的檔案名稱、行號為,我們注意到有一個比較陌生的資訊:{58}。這個整數值代表了什麼意思呢?
其實,它代表了第幾次記憶體配置操作。象這個例子,{58}代表了第58次記憶體配置操作發生了泄漏。你可能要說,我只new過一次,怎麼會是第58次?這很容易理解,其他的記憶體申請操作在C的初始化程序呼叫的唄。
有沒有可能,我們讓程式運行到第58次記憶體配置操作的時候,自動停下來,進入調試狀態?所幸,crtdbg確實提供了這樣的函數:即
long _CrtSetBreakAlloc(long nAllocID)。我們加上它:
#define CRTDBG_MAP_ALLOC #include <stdlib.h> #include <crtdbg.h> int main(){_CrtSetBreakAlloc(58);char* pChars = new char[10];_CrtDumpMemoryLeaks();return 0;}
你發現,程式運行到 char* pChars = new char[10];一句時,自動停下來進入調試狀態。細細體會一下,你可以發現,這種方式你獲得的資訊遠比在程式退出時獲得檔案名稱及行號有價值得多。因為報告泄漏檔案名稱及行號,你獲得的只是靜態資訊,然而_CrtSetBreakAlloc則是把整個現場恢複,你可以通過對函數調用棧分析(我發現很多人不習慣看函數調用棧,如果你屬於這種情況,我強烈推薦你去補上這一課,因為它太重要了)以及其他線上調試技巧,來分析產生記憶體流失的原因。通常情況下,這種分析方法可以在5分鐘內找到肇事者。
PS:在VS2010下使用這兩種方法,宏和標頭檔不用包含也可以正確運行:
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
非MFC程式可以用以下方法檢測記憶體泄露:
1.程式開始包含如下定義:
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif // _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif // _DEBUG
2.程式中添加下面的函數:
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
Debug版本程式運行結束後如有記憶體流失,輸出視窗中會顯示類似資訊:
Detected memory leaks!
Dumping objects ->
g:\programs\test\test.cpp(16) : {51} client block at 0x00385C58, subtype 0, 4 bytes long.
Data: < > CD CD CD CD
Object dump complete.
MFC程式記憶體流失檢測方法:
1.在 CMyApp 中添加如下三個 CMemoryState 類的成員變數:
#ifdef _DEBUG
protected:
CMemoryState m_msOld, m_msNew, m_msDiff;
#endif // _DEBUG
2.在 CMyApp::InitInstance() 中添加如下代碼:
#ifdef _DEBUG
m_msOld.Checkpoint();
#endif // _DEBUG
3.在 CMyApp::ExitInstance() 中添加如下代碼:
#ifdef _DEBUG
m_msNew.Checkpoint();
if (m_msDiff.Difference(m_msOld, m_msNew))
{
afxDump<<"\nMemory Leaked :\n";
m_msDiff.DumpStatistics();
afxDump<<"Dump Complete !\n\n";
}
#endif // _DEBUG
Debug版本程式運行結束後如有記憶體流失,輸出視窗中會顯示類似資訊:
Memory Leaked :
0 bytes in 0 Free Blocks.
8 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 8825 bytes.
Total allocations: 47506 bytes.
Dump Complete !
Detected memory leaks!
Dumping objects ->
g:\programs\chat\chatdlg.cpp(120) : {118} normal block at 0x00D98150, 8 bytes long.
Data: < > A8 7F D9 00 01 00 00 00
Object dump complete.