一般来说,都是通过重载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
}
输出成功:

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

711

被折叠的 条评论
为什么被折叠?



