MFC記憶體洩露與檢測
記憶體洩露的含義是:拿走了一塊“堆”記憶體塊,在某檢查點處,發現沒有歸還這個記憶體塊。如果是: 地址A = malloc(N); 因為沒有呼叫free(地址A),所以記憶體洩露了。如果是: 地址B = new 型別T; 因為沒有呼叫delete 地址B,所以記憶體洩露了。如果是:從使用者的記憶體池中取一個記憶體塊,沒有呼叫相應的歸還給記憶體池的操作,也認為是“記憶體洩露”。從哪裡拿了一個東西,要歸還到那個地方去。例如:從圖書館L中借了本書,歸還給圖書館B,肯定要捱罵的。同理,從圖書館L中借了本小說,卻還給圖書館一本雜誌,也是要捱罵的。函式_CrtDumpMemoryLeaks()功能:檢查記憶體洩露並且在VC的輸出視窗列印出洩露的記憶體塊資訊。
例子1 :
- #include
- #include
- int main()
- {
- int* x = new int();
- _CrtDumpMemoryLeaks()
- return 0;
- }
輸出:
Detected memory leaks!
Dumping objects -> {61} normal block at 0x00382650, 4 bytes long. Data: < > 00 00 00 00
非常好,發現了int* x對應的記憶體塊洩露了
例子2 :
- template struct Test
- {
- Test()
- {m_p = new char[Size];}
- ~Test()
- { delete[] m_p;}
- char* m_p;
- };
- Test<123> t;
- int main()
- {
- int* x = new int();
- _CrtDumpMemoryLeaks() ;
- }
Detected memory leaks!
{62} normal block at 0x00382708, 4 bytes long.
{61} normal block at 0x00382650, 123 bytes long.
非常不好,它把全域性變數t也報告了。這是一個嚴重的誤報。
原因是在_CrtDumpMemoryLeaks()呼叫時,全域性變數t還沒有離開生存期呢,所以此時~Test()未呼叫呢,delete[] m_p還沒呼叫呢。
例子3 :
- Test<123> t;
- int main()
- {
- _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- int* x = new int();
- return 0;
- }
輸出:
Detected memory leaks!
{62} normal block at 0x00382708, 4 bytes long.
非常好,通過_CrtSetDbgFlag函式,告知Crt庫在程式完全退出時,列印一下記憶體洩露的情況。
這時,全域性變數t已經析構了,所以誤報沒有了。
例子4 :
- #include<iostream>
- using namespace std;
- #define DEBUG_NEW new(/*_NORMAL_BLOCK,*/ __FILE__, __LINE__)
- #define new DEBUG_NEW
- int main()
- {
- _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- int* x = new int();
- return 0;
- }
輸出:
Detected memory leaks!
c:/sdfdfsdf/sdfdfsdf.cpp(14) :
{61} normal block at 0x00382650, 4 bytes long.
太酷了!居然在除錯的輸出視窗中,顯示了造成記憶體洩露的程式碼位置。
雙擊一下,還能自動跳到文字編輯器中對應的程式碼行上。
例子5 :
- #include<iostream>
- using namespace std;
- int main()
- {
- _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
- std::cout<<"hello world"<<endl;
- return 0;
- }
呼叫堆疊視窗。看到一些函式的呼叫關係,順著點點看看,居然發現了int* x = new int;這一行。
這個62是怎麼知道的呢?原來在記憶體洩露的輸出資訊裡,
如下所示:
Detected memory leaks!
{62} normal block at 0x00382708, 4 bytes long.
大括號中62就是第62次分配記憶體時,這塊記憶體洩露了。通過_CrtSetBreakAlloc呼叫,告知Crt庫,在第62次分配記憶體的呼叫時,自動暫停程式,讓程式設計師檢查函式呼叫棧。如何保證下次程式執行時,
第62此分配記憶體的呼叫就是int* x = new int;這句造成的呢?
答案是不能。如果程式沒有複雜的時序相關的邏輯(多執行緒),輸入的值是一定的,則程式每次執行的行為是一定的。
例子8 :
- class Init_before_main
- {
- public: Init_before_main()
- { _CrtSetBreakAlloc(62);
- }
- };
- Init_before_main g_tmp;
- int main()
- {
- int* x = new int;
- return 0;
- }
這是對例子7的一點改進,保證在int* x = new int;呼叫之前,調_CrtSetBreakAlloc(62);。
否則,如下的呼叫順序可能會漏過了第62次分配呼叫 int* x = new int; _CrtSetBreakAlloc(62);
如何自己實現記憶體洩露檢查工具呢?思路很簡單,過載new,delete運算子,使用自己巨集替換malloc和free。
所有的分配和釋放動作必須經過我過手,我才能加入點私貨(統計資訊等)。這樣就可以檢查記憶體洩露了。
附:
1、對於類似這樣的記憶體洩露提示:
Detected memory leaks!
Dumping objects ->
{223} normal block at 0x003CF650, 4 bytes long.
Data: < < > E8 F6 3C 00
我們可以利用CRT函式_CrtSetBreakAlloc(223); 進行定位。
這個函式,就設定了當分配上面223那塊記憶體時,就中斷,然後就可以檢視呼叫棧,知道那裡出錯了。不過,使用這個來判斷,就要仔細地分析了,由於記憶體的分配是動態的,並不能保證每次分配記憶體的號碼是一樣的。
2、記憶體洩露的全域性觀念
- <span style="font-size:14px;">#include "stdafx.h"
- #include <afx.h>
- class CMyClassIncString
- {
- public:
- CMyClassIncString()
- {
- m_str = _T("hello, word");
- m_str2 = _T("memleaking ?");
- }
- protected:
- private:
- CString m_str;
- CString m_str2;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- CMyClassIncString* str = new CMyClassIncString;
- return 0;
- }</span>
上面的程式導致了下面的結果,
Detected memory leaks!
Dumping objects ->
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {543} normal block at 0x0003FE68, 42 bytes long.
Data: < x > 0C 00 E5 78 0C 00 00 00 0C 00 00 00 01 00 00 00
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {542} normal block at 0x0003FE00, 40 bytes long.
Data: < x > 0C 00 E5 78 0B 00 00 00 0B 00 00 00 01 00 00 00
{541} normal block at 0x0003FDB8, 8 bytes long.
Data: < x > 10 FE 03 00 78 FE 03 00
Object dump complete.
原因是包含CString物件的物件沒有被釋放.
不要光盯著CString,應該盯著使用CString作類成員的物件是否被正常釋放.
參考資料:
http://msdn.microsoft.com/en-us/library/x98tx3cf.aspx
http://vld.codeplex.com/
相關文章
- MFC 檢測記憶體洩漏的方法記憶體
- Android 檢測記憶體洩露Android記憶體洩露
- C程式記憶體洩露檢測工具——ValgrindC程式記憶體洩露
- 在iOS上自動檢測記憶體洩露iOS記憶體洩露
- vs2008下的MFC程式,怎麼檢測記憶體洩露C程式記憶體洩露
- Android記憶體優化——記憶體洩露檢測分析方法Android優化記憶體洩露
- MLeaksFinder:精準 iOS 記憶體洩露檢測工具iOS記憶體洩露
- LeakCanary 傻瓜式的記憶體洩露檢測工具記憶體洩露
- LeakCanary傻瓜式的記憶體洩露檢測工具記憶體洩露
- 記憶體洩露記憶體洩露
- java中如何檢視記憶體洩露Java記憶體洩露
- 如何在vs下linux下檢測記憶體洩露Linux記憶體洩露
- JVM與記憶體洩露問題JVM記憶體洩露
- js記憶體洩露JS記憶體洩露
- JavaScript記憶體洩露JavaScript記憶體洩露
- 記憶體洩露嗎記憶體洩露
- SHBrowseForFolder 記憶體洩露記憶體洩露
- 【YFMemoryLeakDetector】人人都能理解的 iOS 記憶體洩露檢測工具類iOS記憶體洩露
- 使用新版Android Studio檢測記憶體洩露和效能Android記憶體洩露
- iOS檢測記憶體洩漏iOS記憶體
- 如何檢測記憶體洩漏記憶體
- 記憶體溢位和記憶體洩露記憶體溢位記憶體洩露
- ArkTS 的記憶體快照與記憶體洩露除錯記憶體洩露除錯
- Lowmemorykiller記憶體洩露分析記憶體洩露
- LeakCanary(二)記憶體洩露監測原理研究記憶體洩露
- malloc_stats---檢查記憶體洩露的神器記憶體洩露
- 檢視 Node.js 中的記憶體洩露Node.js記憶體洩露
- JavaScript記憶體洩漏檢測工具JavaScript記憶體
- 使用 mtrace 分析 “記憶體洩露”記憶體洩露
- 實戰Go記憶體洩露Go記憶體洩露
- js記憶體洩露的原因JS記憶體洩露
- Java記憶體洩露的原因Java記憶體洩露
- JAVA 記憶體洩露的理解Java記憶體洩露
- IE中的記憶體洩露記憶體洩露
- 學習Java:記憶體洩露Java記憶體洩露
- C++記憶體洩露檢查的5個方法C++記憶體洩露
- linux下檢查記憶體洩露的工具--mtraceLinux記憶體洩露
- 使用 Instruments 檢測記憶體洩漏記憶體