vs中檢測內存泄漏的方法

使用vs的內存檢測有以下幾種方法。

在debug模式下以F5運行:

方法一:

[html] view plain copy
  1. #define CRTDBG_MAP_ALLOC    
  2. #include <stdlib.h>    
  3. #include <crtdbg.h>    
  4. //在入口函數中包含 _CrtDumpMemoryLeaks();    
  5. //即可檢測到內存泄露  
  6.   
  7. //以如下測試函數爲例:  
  8. int main()  
  9. {  
  10.     char* pChars = new char[10];  
  11.     _CrtDumpMemoryLeaks();  
  12.     return 0;  
  13. }  

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.{}中的數字指明這塊內存是程序中總計第幾個被申請的,這種方法沒有行號和其他信息輸出。我們可以定義:

[html] view plain copy
  1. #ifdef _DEBUG  
  2. #define New   new(_NORMAL_BLOCK, __FILE__, __LINE__)  
  3. #endif  
  4.   
  5. #define CRTDBG_MAP_ALLOC    
  6. #include <stdlib.h>    
  7. #include <crtdbg.h>    
  8. //在入口函數中包含 _CrtDumpMemoryLeaks();    
  9. //即可檢測到內存泄露  
  10.   
  11. //以如下測試函數爲例:  
  12. int main()  
  13. {  
  14.     char* pChars = New char[10];  
  15.     _CrtDumpMemoryLeaks();  
  16.     return 0;  
  17. }  

輸出:

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.

方法二:

[html] view plain copy
  1. #define CRTDBG_MAP_ALLOC    
  2. #include <stdlib.h>    
  3. #include <crtdbg.h>    
  4. //在入口函數中包含 _CrtDumpMemoryLeaks();    
  5. //即可檢測到內存泄露  
  6.   
  7. //定義函數:  
  8. inline void EnableMemLeakCheck()  
  9. {  
  10.     _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);  
  11. }  
  12. //該函數可以放在主函數的任意位置,都能正確的觸發內存泄露輸出  
  13.   
  14.   
  15. //以如下測試函數爲例:  
  16. int main()  
  17. {  
  18.     EnableMemLeakCheck();  
  19.     char* pChars = new char[10];  
  20.     //_CrtDumpMemoryLeaks();  
  21.     return 0;  
  22. }  

輸出:

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)。我們加上它:

[html] view plain copy
  1. #define CRTDBG_MAP_ALLOC    
  2. #include <stdlib.h>    
  3. #include <crtdbg.h>    
  4.   
  5. int main()  
  6. {  
  7.     _CrtSetBreakAlloc(58);  
  8.     char* pChars = new char[10];  
  9.     _CrtDumpMemoryLeaks();  
  10.     return 0;  
  11. }  

你發現,程序運行到 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.

發佈了29 篇原創文章 · 獲贊 28 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章