如何检测内存泄露

C++大量的手动分配、回收内存是存在风险的,很有可能因为我们的操作不当导致内存泄露的问题。

介绍一种在Debug模式下测试内存泄露的方法。
先在文件的开头加上如下代码,切记顺序不可以改变。

#define _CRTDBG_MAP_ALLOC
#include<crtdbg.h>
#include <stdlib.h>

第一行的宏,是实现一些内存分配函数向Debug模式的映射。

接下来,对new做一个重定义。

#define NEW_WITH_MEMORY_LEAR_CHECKING new(_NORMAL_BLOCK,__FILE__,__LINE__)
#define new NEW_WITH_MEMORY_LEAR_CHECKING

这里的new采用的是VC++对operator new的一个重载,在< vcruntime_new_debug.h>定义。

完成上边的两步后,程序中new和delete回收的过程中便被VC++监视了,在程序退出的地方调用以下函数检测内存泄露。

_CrtDumpMemoryLeaks();

函数将显示当前内存泄露,也就是程序运行到此行代码时的内存泄露,所有未摧毁的对象都会报出内存泄露,因此这个函数尽量放在后面。
举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRTDBG_MAP_ALLOC 
#include<crtdbg.h>
#include <stdlib.h>
#define NEW_WITH_MEMORY_LEAR_CHECKING new(_NORMAL_BLOCK,__FILE__,__LINE__)
#define new NEW_WITH_MEMORY_LEAR_CHECKING
int main(int argc, char* argv)  {
     auto p = new int[1];
     _CrtDumpMemoryLeaks();
     system("pause:");
     return 0;
}

这里写图片描述
VC++的编译器cl.exe在delete后会将内存置为0xcdcd防止再次利用,这是程序结束时p进行回收。

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ),这样无论程序何时终止,都会在终止前调用_CrtDumpMemoryLeaks()。
查找泄露技巧 : 使用_CrtSetBreakAlloc(long lBreakAlloc ),函数参数为内存分配的次数。于是让程序自动在泄露处进入断点,可以在_CrtSetDbgFlag后面添加函数_CrtSetBreakAlloc(18); 然后调试程序时,程序自动中断在第18次分配内存的时的crt代码处,然后只要通过查看调用堆栈就可以轻松看到之前的泄露的代码了 。

也可以在某时刻设置检查点,获取当时内存状态的快照,比较不同时刻内存状态的差异。
1.在关键带你对应用程序的内存状态拍快照。CRT库提供一种结构类型_CrtMemState,可以存储内存状态的快照。

_CrtMemState s1, s2, s3;

2.若要在给定点对内存状态拍快照,向_CrtMemCheckpoin函数传递_CrtMemCheckpoint函数传递_CrtMemState结构。该函数用当前内存状态的快照填充此结构。

_CrtMemCheckpoint(&s1);

3.通过向_CrtMemDumpStatistics函数传递_CrtMemState结构,可以在任意点输出当前内存的状态。

_CrtMemDumpStatistics(&s1);

4.确定代码中部分代码发生内存泄露,可以在该部分之前和之后对内存状态拍快照,然后使用_CrtMemDifference比较这两个状态。

_CrtMemCheckpoint(&s1);
_CrtMemCheckpoint(&s2);

if(_CrtMemDifference(&s3, &s1, &s2))
     _CrtMemDumpStatistics(&s3);

比较s1和s2的内存状态,生成这两个状态之间差异的结果s3。

举个例子:

#define _CRTDBG_MAP_ALLOC //必须放在#include<crtdbg.h>之前
#include<iostream>    
#include<cstring>    
#include<crtdbg.h>
#ifdef _DEBUG //重载new  
#define new  new(_NORMAL_BLOCK, __FILE__, __LINE__)    
#endif
using namespace std;    
int main(int argc,char** argv)  {    
//_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
_CrtSetBreakAlloc(142);
    _CrtMemState s1, s2, s3;  
char* str1=new char[100];
//_CrtMemCheckpoint( &s1 );//记录内存快照  
  //  _CrtMemDumpStatistics( &s1 );//输出  
char* str2=(char*)malloc(sizeof(char)*100);
//_CrtMemCheckpoint( &s2 );  
  //  _CrtMemDumpStatistics( &s2 );  
strcpy(str1,"asdfggg");
strcpy(str2,"123465");
cout<<int('a')<<endl;
//if ( _CrtMemDifference( &s3, &s1, &s2) )//比较s1和s2,把比较结果输出到s3  
  //      _CrtMemDumpStatistics( &s3 );// dump 差异结果  
_CrtDumpMemoryLeaks();
return 0;
}

猜你喜欢

转载自blog.csdn.net/zwe7616175/article/details/81139993
今日推荐