[原创]精确跟踪内存泄漏的方法

本文介绍了一种通过重载malloc和free函数来检测内存泄漏的方法,不仅能够统计分配和释放次数,还能打印未释放变量的详细信息,包括变量名、类型、所在行号及函数名,适用于C/C++程序的内存管理优化。

 一般来说,都是通过重载malloc free 函数 并记录malloc次数与free次数来确定是否有内存泄漏.

这里介绍了我自己的方法,不但可以知道有哪个变量没有free,而且可以打印出这个没有free的变量的名称与所在行.通过define 载入(__LINE__,__FUNCTION__,__FILE__)的方式,把 malloc时的变量名与所在行 都写入 重载的 malloc 函数实现.

我这里同时实现了malloc与new的重载,因为它们不能通用,所以我写了对应的free与delete的重载版本.



#ifndef _DJS_MALLOCFREE_H_ 
	#define _DJS_MALLOCFREE_H_ 
	
//==============================
#ifdef __LEAK__

template<typename KEY,typename VAL,typename IT>inline
int 罒Map~(const KEY&k, unordered_map<KEY,VAL>&Mt,IT&ψ__)
	{
	if(Mt.empty()){printf("★ 罒Map~ Mt.empty()= %d\n",Mt.empty());return 0;}
	// PRINT1if(DJS,"",typeid(ψ__).name());
	// PRINT1if(DJS,"",typeid(Mt.find(k)).name());
	ψ__=Mt.find(k);
	if(ψ__!=Mt.end())
		{
		return true;//找到
		}
	return false;
	}
////////////////////////////////////////////
typedef struct 卍泄漏
	{
	int iMalloc数=0,iNew数=0;
	unordered_map<void*,vector<string>>MψL4str;unordered_map<void*,vector<string>>::iterator ΨMψL4str;
	unordered_map<void*,vector<string>>MψL4strNew;unordered_map<void*,vector<string>>::iterator ΨMψL4strNew;
	//========================================
	卍泄漏(){
					// SET_NAME(".MψL4str",MψL4str)	SET_NAME(".MψL4str",MψL4strNew)	
					}
	//========================================
	void 十十(void*ψ,const char*s变量,const char*sType,unsigned 行 ,const char *s函数,const char *s文件)
		{
		printf("十十ψ= 〔 %p,s变量=%s 〕-----------行:%d,文件:%s\n",ψ,s变量,行,s文件);
		char s行[10];sprintf(s行, "%d", 行);//int转字符串
		MψL4str[ψ]={s变量,sType,s行,s函数};//printf("〔%s,	%s,	%s〕",MψL4str[ψ][0],MψL4str[ψ][1],MψL4str[ψ][2]);
		++iMalloc数;
		#ifdef _PT_LEAK_
			// printf("▍▍	 s变量=%s,  sType=%s	\n",s变量,sType);//TRY_CATCH(printf(" tryψ= %s\n",ψ),printf("!!不是 char* \n"))		
		#endif
		}
	//========================================
	void 一一(void*ψ,unsigned 行,const char *s函数,const char *s文件)
		{
		printf("一一ψ=〔 %d 〕-----------行:%d,文件:%s\n",ψ,行,s文件);
		if(罒Map~(ψ,MψL4str,ΨMψL4str))
			{vector<string>&L4str=ΨMψL4str->second;
			--iMalloc数;
			// #ifdef _PT_LEAK_
				printf("▃▃free变量:iMalloc数=%d 〔变量名=%s, 类型=%s, 行=%s, 函数=%s〕\n",iMalloc数,L4str[0].c_str(),L4str[1].c_str(),L4str[2].c_str(),L4str[3].c_str());
			// #endif
			MψL4str.erase(ψ);
			}
		}
	//===NEW=====================================
	void 十十new(void*ψ,const char*s变量,const char*sType,unsigned 行 ,const char *s函数,const char *s文件)
		{
		printf("十十newψ= %p,-----------行:%d,文件:%s\n",ψ,行,s文件);
		char s行[10];sprintf(s行, "%d", 行);//int转字符串
		MψL4strNew[ψ]={s变量,sType,s行,s函数};//printf("(%s,	%s,	%s)",MψL4str[ψ][0],MψL4str[ψ][1],MψL4str[ψ][2]);
		++iNew数;
		// #ifdef _PT_LEAK_
			printf("▍▍▍ iNew数= %d,	s变量=%s,	 sType=%s	\n",iNew数,s变量,sType);//TRY_CATCH(printf(" tryψ= %s\n",ψ),printf("!!不是 char* \n"))		
		// #endif
		}
	//========================================
	void 一一new(void*ψ,unsigned 行,const char *s函数,const char *s文件)
		{
		printf("一一newψ= %d,-----------行:%d,文件:%s\n",ψ,行,s文件);
		if(罒Map~(ψ,MψL4strNew,ΨMψL4strNew))
			{
			vector<string>&L4str=ΨMψL4strNew->second;
			--iNew数;
			// #ifdef _PT_LEAK_
				printf("▃▃▃iNew数= %d,〔变量名=%s,类型=%s,行=%s,函数=%s〕\n",iNew数,L4str[0].c_str(),L4str[1].c_str(),L4str[2].c_str(),L4str[3].c_str());
			// #endif
			MψL4strNew.erase(ψ);
			}
		}
	//========================================
	~卍泄漏()
		{printf(" ▓ ▓ ~~~泄漏 iMalloc数= %d,iNew数= %d\n",iMalloc数,iNew数);
		for(const auto&ψ:MψL4str)
			{
			const vector<string>&L4str=ψ.second;
			printf("未free变量:%d 〔变量名=%s, 类型=%s, 行=%s, 函数=%s〕\n",ψ.first,L4str[0].c_str(),L4str[1].c_str(),L4str[2].c_str(),L4str[3].c_str());
			}
		for(const auto&ψ:MψL4strNew)
			{
			const vector<string>&L4str=ψ.second;
			printf("未delete变量:%d 〔变量名=%s, 类型=%s, 行=%s, 函数=%s〕\n",ψ.first,L4str[0].c_str(),L4str[1].c_str(),L4str[2].c_str(),L4str[3].c_str());
			}
		}
	
	}卍泄漏;
	
////////////////////////////////////////////
	static 卍泄漏 泄漏G;
	//==============================
	// EXCC	 int 卩泄漏() {printf(" ▓ ▓ iMalloc数= %d\n",泄漏G.iMalloc数);return 泄漏G.iMalloc数;}
	//------------------------------
	// #define 亖LIEAK(T)	{printf("type=	%s\n",#T);}
	#define LEAK十十(ψ)	泄漏G.十十(ψ,#ψ,typeid(ψ).name(),__LINE__,__FUNCTION__,__FILE__);
	#define LEAK一一(ψ)	泄漏G.一一(ψ,__LINE__,__FUNCTION__,__FILE__);
	#define LEAK十十new(ψ)	泄漏G.十十new(ψ,#ψ,typeid(ψ).name(),__LINE__,__FUNCTION__,__FILE__);
	#define LEAK一一new(ψ)	泄漏G.一一new(ψ,__LINE__,__FUNCTION__,__FILE__);
	//------------------------------
	#else
		// EXCC	 void 卩泄漏(){}
		  
		// #define 亖LIEAK(T)
		#define LEAK十十(ψ)
		#define LEAK一一(ψ)
		#define LEAK十十new(ψ)
		#define LEAK一一new(ψ)		
#endif	//__LEAK__
//------------------------------


////malloc/////////////////////////////////
static int jSizeMalloc,jSizeЖMalloc,jSizeЖЖ;
#define MALLOC(i维,T,ψ_)		T*ψ_=(T*)malloc(sizeof(T )*(i维));	 LEAK十十(ψ_)
#define MALLOC_(i维,T,ψ_)	 ψ_=(T*)malloc(sizeof(T )*(i维));	 LEAK十十(ψ_)
#define MALLOC冖_(i维,T,ψ_,冖)	   MALLOC_(i维,T,ψ_)	二(i维,冖);
#define MALLOC2(i维,j维,T,ψΨ__)	\
	jSizeMalloc=sizeof(T );jSizeЖMalloc=(sizeof(T*));\
	T**ψΨ__= (T**) malloc(jSizeЖMalloc*(i维));LEAK十十(ψΨ__)	\
	for(int i=0; i	<  (i维); ++i)\
		{ψΨ__[i] =(T*) malloc(jSizeMalloc*(j维));LEAK十十(ψΨ__[i])	} 

	
#define MALLOC2_(i维, j维,T, ψΨ__)	\
	int i,j;jSizeMalloc=sizeof(T );\
	MALLOC_(i维,T*,ψΨ__)\
	for(i=0; i	<  i维; ++i)\
		{ψΨ__[i] =(T*) malloc(jSizeMalloc*(j维));LEAK十十(ψΨ__[i])	}

	
#define MALLOC3(i维,j维,k维,T, ψΨΨ__)	 \
	jSizeMalloc=sizeof(T );jSizeЖMalloc=(sizeof(T*));jSizeЖЖ=(sizeof(T**));\
	T*** ψΨΨ__= (T***) malloc(jSizeЖЖ*(i维));LEAK十十(ψΨΨ__)  \
	for(int i=0; i	<  (i维);++i)\
		{ψΨΨ__[i] =(T**) malloc(jSizeЖMalloc*(j维));LEAK十十(ψΨΨ__[i]) }\
	for(int i=0; i	<  (i维);++i)\
		{\
		for(int j=0; j	<  (j维);++j)\
			{ψΨΨ__[i][j] =(T*) malloc(jSizeMalloc*(k维));LEAK十十(ψΨΨ__[i][j]) }\
		}\
	
		
#define MALLOC3_(i维,j维,k维,T, ψΨΨ__)	  \
	jSizeMalloc=sizeof(T );jSizeЖMalloc=sizeof(T*));jSizeЖЖ=sizeof(T**);\
	MALLOC_(i维,T**,ψΨΨ__)	\
	for(int i=0; i	<  (i维);++i)\
		{ψΨΨ__[i] =(T**) malloc(jSizeЖMalloc*(j维));LEAK十十(ψΨΨ__[i]) }\
	for(int i=0; i	<  (i维);++i)\
		{\
		for(int j=0; j	<  (j维);++j)\
			{ψΨΨ__[i][j] =(T*) malloc(jSizeMalloc*(k维));LEAK十十(ψΨΨ__[i][j]) }\
		}


	
//====realloc==========================
#define	 REALLOC_(i维, T,ψ__)\
	if(ψ__)\
		{T*ψ吅=ψ__;ψ__=(T*)realloc(ψ__,sizeof(T)*(i维));\
		if(ψ__ 二二 nullptr)\
			{LEAK一一(ψ__)	free(ψ吅);ψ__=(T*)malloc(sizeof(T) *(i维));}\
		} \
	else \
		{ψ__=(T*)malloc(sizeof(T) *(i维));LEAK十十(ψ__)	}
	

	
#define	 REALLOC冖_(i维, T,ψ__,冖)	 REALLOC_(i维, T,ψ__,冖)	二(i维,冖);

#define REALLOC2_(i维,j维,T,ψΨ__)	\
	int i,j;jSizeMalloc=sizeof(T );\
	REALLOC_(i维,T,ψΨ__)	\
	T*ψ吅2=ψΨ__[i];\
	for(i=0; i	<  i维; ++i)\
		{ψ吅2=ψΨ__[i];ψΨ__[i]=(T*)realloc(ψΨ__[i],jSizeMalloc*(j维));\
		if(ψΨ__[i] 二二 nullptr)\
			{LEAK一一(ψΨ__[i])	free(ψ吅2);ψΨ__[i]=(T*)malloc(jSizeMalloc*(j维));LEAK十十(ψΨ__[i])	}\
		}


#define 冖MAL(ψ)	   (*(int*)(ψ - 16));

//====free==========================
#define FREE(t)	   LEAK一一(t)	free(t);t=nullptr;

#define FREE2(i维,ψΨ__)\
	int i;LEAK一一(ψΨ__)\
	for(i=0;i < i维;++i)\
		{LEAK一一(ψΨ__[i])	free((void*)ψΨ__[i]);}\
	free((void*)ψΨ__);ψΨ__=nullptr;
	
	

#define FREE3( i维, j维,ψΨΨ__)\
	int i,j;\
   for(i=0;i < i维;++i)\
		for( j=0; j	 <	j维;++j)\
			{LEAK一一(ψΨΨ__[i][j])	free((void*)ψΨΨ__[i][j]);}\
   for(i=0;i < i维;++i)\
		{LEAK一一(ψΨΨ__[i])	free((void*)ψΨΨ__[i]);}\
   LEAK一一(ψΨΨ__)	free((void*)ψΨΨ__);ψΨΨ__=nullptr;

	
////NEW////////////////////////////////////////
#define NEW_A(i维,T,ψ_)	{T*ψ_=new T[i维];LEAK十十new(ψ_)	}
#define NEW_AA(i维,j维,T,ψ_)	\
	T*ψ_=new T*[i维];LEAK十十new(ψ_)	\
	for(int	 i=0;	i<i维;	++i)  \
		{ψ_[i]=new T[j维];LEAK十十new(ψ_[i])	}
	
	
#define NEW_A_(i维,T,ψ_)	{ψ_=new T[i维];LEAK十十new(ψ_)	}
#define 灬NEW_A_(i维,T,ψ_)	\
	LEAK十十new(ψ_)	\
	if (ψ_) {delete [] (ψ_);LEAK一一new(ψ_)	ψ_=new T[i维]; }\
	else	{ψ_=new T[i维];	}\
	
	
#define NEW吅_A_(size旧,size新,T,t旧,t新__)/* 动态内存追加函数 */\
	bool b新=false;\
	if(size旧!=size新 &&t新__){delete [] t新__;LEAK一一new(t新__)	t新__=new T[size];LEAK十十new(t新__)	}\
	memcpy(t新__,t旧,size*sizeof(T));\
	delete [] t旧;LEAK一一new(t旧)	


#define NEW_AA_(i维,j维,T,ψ_)	\
	LEAK十十new(ψ_)	\
	ψ_=new T*[i维];\
	for(int	 i=0;	i<i维;	++i)  \
		ψ_[i]=new T[j维];\
	

#define 灬NEW_AA_(i维,j维,T,ψ_)	\
	if (ψ_) {delete [] (ψ_);LEAK一一new(ψ_)}\
	else	\
		{\
		ψ_=new T*[i维];LEAK十十new(ψ_)	\
		for(int	 i=0;	i<i维;	++i)  \
			{ψ_[i]=new T[j维];LEAK十十new(ψ_[i])	}\
		}


#define DELETE(ψ_)		{ if (ψ_){LEAK一一new(ψ_)	delete (ψ_); (ψ_) = NULL;} }
#define DELETE_A(ψ_)	{ if (ψ_) {LEAK一一new(ψ_)   delete [] (ψ_); (ψ_) = NULL;} }
#define DELETE_AA(i维,ψ_)	\
	if (ψ_) \
		{LEAK一一new(ψ_)	\
		for(int	 i=0;	i<i维;	++i)  \
			{LEAK一一new(ψ_[i])	delete[]ψ_[i];(ψ_)=NULL;}\
		}


//====s====================================================
#if(defined __PRINT__) 
	#define MALLOC_NAME(s名,name)	 if(s名){MALLOC_(strlen(s名)+1,char,name)	S_S(s名,name);}
	#define REALLOC_NAME(s名,name)	   if(s名){REALLOC_(strlen(s名)+1,char,name)	S_S(s名,name);}
	#define RMALLOC_NAME卩(s名,name)		if(s名){if(name){REALLOC_(strlen(s名)+1,char,name)	}	else {MALLOC_(strlen(s名)+1,char,name)	}	S_S(s名,name); }

	#define FREE_NAME(name)	   if((name)!=nullptr){FREE(name)	}/* PRINT1("~~",name); */
	#else
		#define MALLOC_NAME(s名,name)  
		#define REALLOC_NAME(s名,name)
		#define RMALLOC_NAME卩(s名,name)		  
		#define FREE_NAME(name) 
#endif
////END////END////END////END////END////END////END////END////

#endif
	

把上面这个文件保存为 MALFREE.c

于是用main测试一下:

#define __LEAK__ 
#define _PT_LEAK_
#define __PRINT__
#include<string>
#include<unordered_map>
using namespace std;
#include"MELFREE.c"

//==============================    

void main()
    {
    int *ψI;MALLOC_(3,int,ψI);
    
    float *ψF2;MALLOC_(3,float,ψF2);
    double *ψD2;MALLOC_(3,double,ψD2);
	
    FREE(ψF2)//只free了 ψF2 
    }

输出成功:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值