內存泄露的含義是:拿走了一塊“堆”內存塊,在某檢查點處,發現沒有歸還這個內存塊。 如果是: 地址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()
}
輸出:
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();
}
輸出:
Detected memory leaks!
{62} normal block at 0x00382708, 4 bytes long.
非常好,通過_CrtSetDbgFlag函數,告知Crt庫在程序完全退出時,打印一下內存泄露的情況。
這時,全局變量t已經析構了,所以誤報沒有了。
例子4 :
#include
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();
}
輸出:
Detected memory leaks!
c:/sdfdfsdf/sdfdfsdf.cpp(14) :
{61} normal block at 0x00382650, 4 bytes long.
太酷了!居然在調試的輸出窗口中,顯示了造成內存泄露的代碼位置。
雙擊一下,還能自動跳到文本編輯器 中對應的代碼行上。
例子5 :
#include int main()
{ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
std::cout<<"hello world"<
調用堆棧窗口。 看到一些函數的調用關係,順着點點看看,居然發現了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。
所有的分配和釋放動作必須經過我過手,我才能加入點私貨(統計信息等)。這樣就可以檢查內存泄露了。