具有動態的分配和釋放內存的能力是C/C++程序語言的重要特色之一。VisualC++ debugger和CRT庫提供了一系列有效的檢測和鑒定內存洩漏的工具。
設置內存洩漏檢測
檢測內存洩漏的基本工具是調試器和CRT調試堆函數。為了使用調試堆函數,在你的程序中你必須含有下面的說明:
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
必須保證上面聲明的順序,如果改變了順序,可能不能正常工作。<crtdbg.h>的_malloc_dbg和_free_dbg將取代標准的malloc和free函數出現在DEBUG版中,它可以跟蹤內存的分配和釋放。但是這只會在DEBUG版本中發生(當#define _DEBUG的時候),而Release版本仍使用標准的malloc和free功能。
#define _CRTDBG_MAP_ALLOC表示使用CRT堆函數的相應的DEBUG版本。這個定義不是必須的,但是沒有它,內存洩漏報告含有的只是沒有什麼用處的信息。
一旦你已經添加了剛才的聲明,你就能夠通過在程序中加入下面的代碼來報告內存洩漏信息:
_CrtDumpMemoryLeaks();
當在DEBUG模式下運行程序時,在Output窗口的Debug標簽處_CrtDumpMemoryLeaks會顯示內存洩漏的信息,例如:
Detected memory leaks!
Dumping objects ->
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 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,內存洩漏報告就會像下面這樣:
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
由此可見,定義_CRTDBG_MAP_ALLOC時,_CrtDumpMemoryLeaks可以提供更多的有用信息。
如果沒有定義_CRTDBG_MAP_ALLOC,那麼內存洩漏報告如下顯示:
內存分配數值(花括號內)
模塊的類型(normal、clIEnt或者CRT)
以十六進制格式定位的內存
以字節計模塊的大小
第一個十六字節的內容(也可以用十六進制)
如果定義了_CRTDBG_MAP_ALLOC,報告的內容還包括出現分配所洩漏內存的文件。在文件名之後括號內的數字是文件內的行數值。
此時雙擊包含行數值和文件名的輸出行, 或者選擇輸出行並按F4:
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at 0x00780E80, 64 bytes long.
編輯窗口將會跳到文件中分配所洩漏內存的那一行代碼,leaktest.cpp中的行號為20的那一行。
使用_CrtSetDbgFlag
如果你的程序只在一個地方退出,那麼在選擇調用_CrtDumpMemoryLeaks的位置是非常容易的。但是,如果你的程序可能會在程序多處位置退出該怎麼辦?如果不希望在每一個可能的出口處調用_CrtDumpMemoryLeaks,那麼你可以在你的程序開始處包含下面的調用:
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
當程序退出時,將會自動地調用_CrtDumpMemoryLeaks(必須設置_CRTDBG_ALLOC_MEM_DF和 _CRTDBG_LEAK_CHECK_DF)。
翻譯內存模塊的類型
內存洩漏報告中把每一塊洩漏的內存分為普通塊、客戶塊和CRT塊。事實上,你只需要留心普通塊和客戶塊類型。
普通塊(normal block):是由你的程序分配的內存。
客戶塊(clIEnt block):是一種特殊的內存塊,它是由MFC使用的一個對象,程序退出時,該對象的析構函數沒有被調用。MFC new操作符可以用來創建普通塊和客戶塊。
CRT塊(CRT block):是由C RunTime Library供自己使用而分配的內存塊。CRT庫自己來管理這些內存的分配與釋放,通常你不會在內存洩漏報告中發現有CRT內存洩漏,除非程序發生了嚴重的錯誤(例如CRT庫崩潰)。
下面這兩種類型的內存塊不會出現在內存洩漏報告中:
空閒塊(free block):已經被釋放(free)的內存塊。
忽略塊(Ignore block):是程序員顯式聲明過不要在內存洩漏報告中出現的內存塊
設置CRT報告樣式
通常_CrtDumpMemoryLeaks()會dump內存洩漏的信息到output窗口的Debug欄位。你可以使用_CrtSetReportMode()來重新設置輸出到另一個位置。關於更詳細的如何使用_CrtSetReportMode()說明,請查看MSDN。
在內存分配數目處設置一個斷點
在內存洩漏報告中的文件名和行號可告訴分配洩漏的內存的代碼位置,但是光是有這些信息對於完整了解洩漏原因,有時候還是不夠的。因為一個程序在運行時,一段分配分配內存的代碼將會被調用很多次,但可能是某次調用後沒有釋放內存而導致了洩漏內存。為了確定是那些內存沒有被釋放,你必須不僅要知道洩漏的內存在那裡被分配,還要知道洩漏產生的條件。對你來說,有幫助的信息就是內存分配號——在文件名和行號之後的花括號對中出現的數值。
例如,在下面的輸出信息中,"18"是內存分配號,意思是洩漏的內存是你程序中分配的第十八個內存塊:
Detected memory leaks!
Dumping objects ->
C:PROGRAM FILESVISUAL STUDIOMyProjectsleaktestleaktest.cpp(20) : {18} normal block at
0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
CRT庫為在程序運行期間分配的所有內存模塊計數,包括CRT自己分配的內存或者諸如MFC等分配的其它模塊。因此帶有分配號n的一個對象是在你的程序中分配的第n個對象,但不代表是由那段代碼分配的第n個對象(在大部分情況下,它都不會是。)
這樣的話,你可以利用分配號在內存分配的地方設置一個斷點。為了設置這樣一個端點,你可以在你的程序開始處,設置一個位置斷點。當你的程序在那一點break時,你就能夠從QuickWatch對話框或者Watch窗口設置這樣一個位置斷點。
例如,在Watch窗口中,在Name欄鍵入下面的表達式:
_crtBreakAlloc
如果你正在用CRT庫dynamic-link library (DLL)的多線程版本,你必須含有上下文操作符,像這樣:
{,,msvcrtd.dll}_crtBreakAlloc
現在按下RETURN鍵,調試器找到該值並把結果放置在value欄。如果你在
[1] [2] 下一頁