【IT168 技术应用】Windows平台上C++开发内存泄漏检查方法,充分的利用调试工具可以非常方便地避免内存泄漏问题。
这里介绍两种方法,互为补充,第一种是VC编译器提供的方法,第二种是专用的内存泄漏检查工具Memmory Validator。这两种方法的基本原理是一样的:内存分配要通过CRT在运行时实现,只要在分配内存和释放内存时分别做好记录,程序结束时对比分配内存和释放内存的记录就可以确定是不是有内存泄漏。其中,第一种方法重载了new操作符,第二种方法是替换了CRT运行时库,在用户程序与运行库之间加了一层,用于记录内存分配情况。两种方法的不同是前者是在编译时完成的,分析内存情况的代码编译到执行文件中,用于程序的debug版本,后一种对编译过程没有影响,在执行过程中截留与CRT的交互信息。
第一种方法是MSDN中介绍了,在需要检查内存分配情况的cpp文件中引用
但这种方法有缺陷,_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;
}
#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;
}