用V C++检测和隔离内存泄漏
生活随笔
收集整理的這篇文章主要介紹了
用V C++检测和隔离内存泄漏
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
具有動態的分配和釋放內存的能力是C/C++程序語言的重要特色之一。Visual C++ debugger 和 CRT庫提供了一系列有效的檢測和鑒定內存泄漏的工具。
設置內存泄漏檢測
檢測內存泄漏的基本工具是調試器和CRT調試堆函數。為了使用調試堆函數,在你的程序中你必須含有下面的說明:
#define _CRTDBG_MAP_ALLOC#include <stdlib.h>#include <crtdbg.h>
#include說明必須按順序說明。如果改變了順序,所用的函數可能不能正常工作。包含crtdbg.h的_malloc_dbg和 _free_dbg將 malloc和free函數映射到測試版中,它可以跟蹤內存的分配和釋放。這種映射僅僅在一個測試體系中發生(也就是說,僅僅當_DEBUG被定義的時候)。釋放的體系使用通常的malloc和 free功能。
#define說明映射CRT堆函數的低級版本到相應的測試版本。這個說明是不需要的,但是沒有它,內存泄漏處含有的只是沒有多大用處的信息。
一旦你已經增加了剛才的說明,你能夠通過在你的程序中包含下面的說明來釋放內存信息:
_CrtDumpMemoryLeaks();
當調試情況下運行程序時,在輸出窗口的Debug 標簽處_CrtDumpMemoryLeaks表現出內存泄漏的信息。內存泄漏信息類似下面這樣:
Detected memory leaks!
Dumping objects ->
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.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的時候,顯示的內容也向你展現了出現泄漏內存所分配地方的文件。在文件名之后括號內的數字(20,以此為例)是文件內的行數值。如果你雙擊包含行數值和文件名的輸出行,
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.cpp(20) : {18} normal block at
0x00780E80, 64 bytes long.
指針將會跳到源文件中內存被分配地方的行(在上面的情況下,leaktest.cpp的行號為20)。選擇輸出行并按F4將有同樣的效果。
使用_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)是一種特殊的內存模塊,它由于需要一個析構函數的對象而被Microsoft Foundation Classes (MFC)所使用。MFC new操作子建立一個普通模塊或者一個客戶模塊,來適合被創建的模塊。
一個CTR模塊是由CRT庫提供自己使用而分配的內存模塊。CRT庫對這些模塊來管理自己的去分配,因此你不可能在內存泄漏報告中注意到這些,除非有些地方有嚴重的錯誤(例如,CRT庫崩潰)。
在內存泄漏信息中有兩種你從來沒有見過的模塊類型:
空閑模塊(free block)是一種被釋放的內存模塊
Ignore block是你已經特殊標記過以至于在內存泄漏報告中不會出現的模塊。
設置CRT報告樣式
像以前的一樣,按默認方式,_CrtDumpMemoryLeaks傾卸內存泄漏信息到輸出窗口的Debug窗格。你可以運用_CrtSetReportMode重新設置它到堆存處,到另一個位置。如果你使用一個庫,它可能重新設置輸出到另一個位置。在這種情況下,你能夠利用下面的說明來設置輸出位置回到輸出窗口:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
關于使用_CrtSetReportMode去發送輸出信息到另一個位置,要看Visual C++文件的_CrtSetReportMode節。
在內存分配數目處設置一個斷點
在內存泄漏報告中的文件名和行號可告訴你泄漏的內存在那里被分配,但是了解內存在那里分配對于鑒定問題不總是充分的。在一個程序運行過程中,經常是一個分配將會被調用很多次,但是它可能在某次調用中泄漏內存。為了確定問題,你必須不但知道泄漏的內存在那里分配,還要知道泄漏發生的條件。對你來說,使它成為可能的那條信息是內存分配號。當那些被顯示的時候,文件名和行號之后,這是在curly brace中出現的數值。例如,在下面的輸出中,"18"是內存分配號。它的意思是泄漏的內存是你程序中內存分配的第十八個模塊。
Detected memory leaks!
Dumping objects ->
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.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個對象。(在大部分情況下,它是不會的。)
你可以利用分配號在內存分配的地方設置一個斷點。為了做這些,你可以距離你的程序開始很近處,設置一個位置斷點。當你的程序在那一點暫停時,你能夠從QuickWatch對話框或者Watch窗口設置這樣一個位置斷點。例如,在Watch窗口中,在Name欄鍵入下面的表達式:
_crtBreakAlloc
如果你正在用CRT庫的多線程的dynamic-link library (DLL)版本,你必須含有上下文操作符,像這里說明的:
{,,msvcrtd.dll}_crtBreakAlloc
現在,按RETURN。調試器評估調用并且把結果放置在Value欄。如果你在內存分配過程中還沒有設置任何斷點,那么這個值是-1。使用你想中斷處內存分配的分配數值來代替Value表中的值--例如,18 去中斷早期在輸出過程中展現的分配。
當你在你感興趣的內存分配處設置斷點之后,你能夠繼續調試。在與從前相同的條件下,運行程序時一定要小心,因而分配的順序不會改變。當你的程序在一個特殊的內存分配點中斷的時候,你能夠查看Call Stack窗口和其他的測試信息來確定在此條件下內存的分配。如果需要的話,你可以繼續從那一點執行程序,以至于了解對象到底發生了什么事,同時還可能確定為了沒有正確地被去分配。(對對象設置一個數據斷點是很有幫助的。)
雖然在調試器中設置內存分配斷點通常更加容易,但是如果你喜歡的話,你可以在你的代碼中設置它們。為了在你的代碼中設置一個內存分配斷點,可以增加這樣一行(對于第十八個內存分配):
_crtBreakAlloc = 18;
最為一個選擇,你可以使用有相同效果的_CrtSetBreakAlloc函數。
_CrtSetBreakAlloc(18);
比較內存狀態
定位內存泄漏的另一個方法就是在關鍵點對應用程序的內存狀態做快照。CRT庫提供了一個結構類型,_CrtMemState。你可以使用它來存儲內存狀態的一個快照。
_CrtMemState s1, s2, s3;
為了在特定點對內存狀態進行快照,可以傳遞一個_CrtMemState結構到he _CrtMemCheckpoint函數。此函數用當時內存狀態的一個快照來填充此結構:
_CrtMemCheckpoint( &s1 );
你可以通過傳遞此結構到_CrtMemDumpStatistics函數來傾卸_CrtMemState結構的任意點的內容:
_CrtMemDumpStatistics( &s3 );( &s1 );
此函數打印出類似于下面這樣的一堆內存分配信息:
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
3071 bytes in 16 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 3071 bytes.
Total allocations: 3764 bytes.
為了確定一個內存泄漏是否在一節代碼中出現,你可以在此節前和此節后對內存狀態作快照,然后用_CrtMemDifference比較兩種狀態:
_CrtMemCheckpoint( &s1 );
// memory allocations take place here
_CrtMemCheckpoint( &s2 );
if ( _CrtMemDifference( &s3, &s1, &s2) )
???_CrtMemDumpStatistics( &s3 );
像名字暗示的一樣,_CrtMemDifference比較兩個內存狀態(最先的兩個參數)并且產生一個不同于這兩個狀態的結果(第三個參數)。在你的程序開始和結尾處的_CrtMemCheckpoint調用和使有_CrtMemDifference來比較結果為檢測內存泄漏提供了另一種方法。如果一個泄漏被檢測到,那么可以使用_CrtMemCheckpoint調用來分割你的程序并且使用二元binary search technique來定位泄漏。
設置內存泄漏檢測
檢測內存泄漏的基本工具是調試器和CRT調試堆函數。為了使用調試堆函數,在你的程序中你必須含有下面的說明:
#define _CRTDBG_MAP_ALLOC#include <stdlib.h>#include <crtdbg.h>
#include說明必須按順序說明。如果改變了順序,所用的函數可能不能正常工作。包含crtdbg.h的_malloc_dbg和 _free_dbg將 malloc和free函數映射到測試版中,它可以跟蹤內存的分配和釋放。這種映射僅僅在一個測試體系中發生(也就是說,僅僅當_DEBUG被定義的時候)。釋放的體系使用通常的malloc和 free功能。
#define說明映射CRT堆函數的低級版本到相應的測試版本。這個說明是不需要的,但是沒有它,內存泄漏處含有的只是沒有多大用處的信息。
一旦你已經增加了剛才的說明,你能夠通過在你的程序中包含下面的說明來釋放內存信息:
_CrtDumpMemoryLeaks();
當調試情況下運行程序時,在輸出窗口的Debug 標簽處_CrtDumpMemoryLeaks表現出內存泄漏的信息。內存泄漏信息類似下面這樣:
Detected memory leaks!
Dumping objects ->
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.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的時候,顯示的內容也向你展現了出現泄漏內存所分配地方的文件。在文件名之后括號內的數字(20,以此為例)是文件內的行數值。如果你雙擊包含行數值和文件名的輸出行,
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.cpp(20) : {18} normal block at
0x00780E80, 64 bytes long.
指針將會跳到源文件中內存被分配地方的行(在上面的情況下,leaktest.cpp的行號為20)。選擇輸出行并按F4將有同樣的效果。
使用_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)是一種特殊的內存模塊,它由于需要一個析構函數的對象而被Microsoft Foundation Classes (MFC)所使用。MFC new操作子建立一個普通模塊或者一個客戶模塊,來適合被創建的模塊。
一個CTR模塊是由CRT庫提供自己使用而分配的內存模塊。CRT庫對這些模塊來管理自己的去分配,因此你不可能在內存泄漏報告中注意到這些,除非有些地方有嚴重的錯誤(例如,CRT庫崩潰)。
在內存泄漏信息中有兩種你從來沒有見過的模塊類型:
空閑模塊(free block)是一種被釋放的內存模塊
Ignore block是你已經特殊標記過以至于在內存泄漏報告中不會出現的模塊。
設置CRT報告樣式
像以前的一樣,按默認方式,_CrtDumpMemoryLeaks傾卸內存泄漏信息到輸出窗口的Debug窗格。你可以運用_CrtSetReportMode重新設置它到堆存處,到另一個位置。如果你使用一個庫,它可能重新設置輸出到另一個位置。在這種情況下,你能夠利用下面的說明來設置輸出位置回到輸出窗口:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
關于使用_CrtSetReportMode去發送輸出信息到另一個位置,要看Visual C++文件的_CrtSetReportMode節。
在內存分配數目處設置一個斷點
在內存泄漏報告中的文件名和行號可告訴你泄漏的內存在那里被分配,但是了解內存在那里分配對于鑒定問題不總是充分的。在一個程序運行過程中,經常是一個分配將會被調用很多次,但是它可能在某次調用中泄漏內存。為了確定問題,你必須不但知道泄漏的內存在那里分配,還要知道泄漏發生的條件。對你來說,使它成為可能的那條信息是內存分配號。當那些被顯示的時候,文件名和行號之后,這是在curly brace中出現的數值。例如,在下面的輸出中,"18"是內存分配號。它的意思是泄漏的內存是你程序中內存分配的第十八個模塊。
Detected memory leaks!
Dumping objects ->
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.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個對象。(在大部分情況下,它是不會的。)
你可以利用分配號在內存分配的地方設置一個斷點。為了做這些,你可以距離你的程序開始很近處,設置一個位置斷點。當你的程序在那一點暫停時,你能夠從QuickWatch對話框或者Watch窗口設置這樣一個位置斷點。例如,在Watch窗口中,在Name欄鍵入下面的表達式:
_crtBreakAlloc
如果你正在用CRT庫的多線程的dynamic-link library (DLL)版本,你必須含有上下文操作符,像這里說明的:
{,,msvcrtd.dll}_crtBreakAlloc
現在,按RETURN。調試器評估調用并且把結果放置在Value欄。如果你在內存分配過程中還沒有設置任何斷點,那么這個值是-1。使用你想中斷處內存分配的分配數值來代替Value表中的值--例如,18 去中斷早期在輸出過程中展現的分配。
當你在你感興趣的內存分配處設置斷點之后,你能夠繼續調試。在與從前相同的條件下,運行程序時一定要小心,因而分配的順序不會改變。當你的程序在一個特殊的內存分配點中斷的時候,你能夠查看Call Stack窗口和其他的測試信息來確定在此條件下內存的分配。如果需要的話,你可以繼續從那一點執行程序,以至于了解對象到底發生了什么事,同時還可能確定為了沒有正確地被去分配。(對對象設置一個數據斷點是很有幫助的。)
雖然在調試器中設置內存分配斷點通常更加容易,但是如果你喜歡的話,你可以在你的代碼中設置它們。為了在你的代碼中設置一個內存分配斷點,可以增加這樣一行(對于第十八個內存分配):
_crtBreakAlloc = 18;
最為一個選擇,你可以使用有相同效果的_CrtSetBreakAlloc函數。
_CrtSetBreakAlloc(18);
比較內存狀態
定位內存泄漏的另一個方法就是在關鍵點對應用程序的內存狀態做快照。CRT庫提供了一個結構類型,_CrtMemState。你可以使用它來存儲內存狀態的一個快照。
_CrtMemState s1, s2, s3;
為了在特定點對內存狀態進行快照,可以傳遞一個_CrtMemState結構到he _CrtMemCheckpoint函數。此函數用當時內存狀態的一個快照來填充此結構:
_CrtMemCheckpoint( &s1 );
你可以通過傳遞此結構到_CrtMemDumpStatistics函數來傾卸_CrtMemState結構的任意點的內容:
_CrtMemDumpStatistics( &s3 );( &s1 );
此函數打印出類似于下面這樣的一堆內存分配信息:
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
3071 bytes in 16 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 3071 bytes.
Total allocations: 3764 bytes.
為了確定一個內存泄漏是否在一節代碼中出現,你可以在此節前和此節后對內存狀態作快照,然后用_CrtMemDifference比較兩種狀態:
_CrtMemCheckpoint( &s1 );
// memory allocations take place here
_CrtMemCheckpoint( &s2 );
if ( _CrtMemDifference( &s3, &s1, &s2) )
???_CrtMemDumpStatistics( &s3 );
像名字暗示的一樣,_CrtMemDifference比較兩個內存狀態(最先的兩個參數)并且產生一個不同于這兩個狀態的結果(第三個參數)。在你的程序開始和結尾處的_CrtMemCheckpoint調用和使有_CrtMemDifference來比較結果為檢測內存泄漏提供了另一種方法。如果一個泄漏被檢測到,那么可以使用_CrtMemCheckpoint調用來分割你的程序并且使用二元binary search technique來定位泄漏。
總結
以上是生活随笔為你收集整理的用V C++检测和隔离内存泄漏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++求矩阵的秩_线性代数复习(被玩坏的
- 下一篇: centos7 php多版本切换_cen