Windows平臺上C++開發內存泄漏檢查方法
充分的利用調試工具可以非常方便地避免內存泄漏問題。
這里介紹兩種方法,互為補充,第一種是VC編譯器提供的方法,第二種是專用的內存泄漏檢查工具Memmory Validator。這兩種方法的基本原理是一樣的:內存分配要通過CRT在運行時實現,只要在分配內存和釋放內存時分別做好記錄,程序結束時對比分配內存和釋放內存的記錄就可以確定是不是有內存泄漏。其中,第一種方法重載了new操作符,第二種方法是替換了CRT運行時庫,在用戶程序與運行庫之間加了一層,用于記錄內存分配情況。兩種方法的不同是前者是在編譯時完成的,分析內存情況的代碼編譯到執行文件中,用于程序的debug版本,后一種對編譯過程沒有影響,在執行過程中截留與CRT的交互信息。
第一種方法是MSDN中介紹了,在需要檢查內存分配情況的cpp文件中引用<stdlib.h>和<ctrdbg.h>兩個頭文件,放于最頭部,再用宏代換的方法用重載后的new操作符代替原來的new操作符,如下列代碼所示,在程序退出的位置調用_CrtDumpMemoryLeaks()輸出全部沒有釋放的內存內容,及申請這些內存的源代碼位置,非常便于調試。
但這種方法有缺陷,_CrtDumpMemoryLeaks()必須在main()函數結束之前調用,所以main()函數中的棧對象還沒有析構,會被當做內存泄漏,如下面代碼中的NewClass類的對象,實際是沒有問題的。另外就是不同編譯器實現非ASCII碼字符時可能會有所不同,如下面代碼中的漢字串都被視為內存泄漏。
#include <stdlib.h>
#include <crtdbg.h>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
struct AlertDescriptionString
{
unsigned int ID;
string Name;
string Desp;
};
const AlertDescriptionString String[] =
{
{0,"AAA","BBBB"},
// memory leak count by _CRTDBG_MAP_ALLOC
{1,"CCC","__XXX__檢測到可能由AirJack發出的數據包"}
};
struct AlertDescriptionStr
{
unsigned int ID;
char* Name;
char* Desp;
};
const AlertDescriptionStr Str[] =
{
{0,"AAA","BBBB"},
{1,"CCC","檢測到可能由AirJack發出的數據包"}
};
void leak_memory(void)
{
vector<unsigned int *> vec;
for( int j = 0; j < 2; j++)
{
vec.push_back(new unsigned int(0));
}
}
class NewClass
{
void * p ;
public:
NewClass()
{
p = (void*) new char[10];
}
~NewClass()
{
delete [] p;
}
};
int * p = new int(9);
int real_main_fun (int argc, char ** argv)
{
leak_memory();
return 0;
}
int main (int argc, char ** argv)
{
string str("__YYY__檢測到可能由AirJack發出的數據包");
NewClass cls;
int i = real_main_fun(argc, argv); // 原有的main函數體
if(_CrtDumpMemoryLeaks())
cout<< " memory leak " << endl;
return i;
}
第二種方法正好是它的補充,Memmory Validator可以檢查程序整個運行過程中的內存分配情況,也可以將內存泄漏的位置顯示出來,如圖所示。
在實際應用第一種方法時,可以采用兩個頭文件,用于大型工程的調試,幾乎不對其他部分代碼產生影響。
-----------------------------------------------------------------------------
//config.h
#define MEMORY_DEBUG
#ifdef MEMORY_DEBUG
#include <stdlib.h>
#include <crtdbg.h>
#endif // MEMORY_DEBUG
------------------------------------------------------------------------------
//debug.h
#ifdef MEMORY_DEBUG
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif // MEMORY_DEBUG
-------------------------------------------------------------------------------
//main.cpp
#include "config.h” // config.h, 第一個頭文件
#include "alertparser.h"
#include "alertinfocache.h"
#include <iostream>
#include <pcap.h>
#include "debug.h" //debug.h, 最后一個頭文件
int main (int argc, char ** argv)
{
int i = real_main_fun(argc, argv); // 原有的main函數體
if(_CrtDumpMemoryLeaks())
cout<< " memory leak " << endl;
return i;
}
RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成