实用小代码之内存泄漏检测(二)
继上次 实用小代码之内存泄漏检测 一文。这次继续介绍另一个我平时用于动态监测内存泄漏的代码。
我这里所说的 动态监测内存泄漏 是指在程序执行时,以替换 malloc 和 free 函数来达到检测内存泄漏的目的,因为内存泄漏的主要来源就是 malloc 和 free 这组函数。相比那些分析源代码的检测工具,动态监测能够很好的检测循环中分配的内存是否被泄露。下面我不想多说,一切以代码来说话。
这里的代码只是给各位一个抛砖引玉的借鉴。其中还有很多不完善的地方。比如没有多线程锁之类的问题。
/*
PROGRAMER: Wayne Huang
DATE: 2008.04.18
LICENCE: GPL v2.0
*/
#define MMALLOC(s) mm_malloc(s,__FILE__,__LINE__)
#define MFREE(p) mm_free(p,__FILE__,__LINE__)
#define MOUTWE "[%s:%d] {%c} 0x%x "
typedef struct mmbs mmbs;
struct mmbs {
mmbs *next;
char *file;
int line;
void *mm;
} ;
static mmbs mhandle = {NULL,0,0,0} ;
mmbs * handle =& mhandle;
void * mm_malloc(unsigned int s, char * file, int line);
void mm_free( void * p, char * file, int line);
void mm_exit( int rel);
void * mm_malloc(unsigned int s, char * file, int line) {
mmbs *p=malloc(sizeof(mmbs)+s);
mmbs *i=NULL;
if(p){
p->next=NULL;
p->file=file;p->line=line;
p->mm=&p[1];
for(i=handle;i->next;i=i->next);
i->next=p;
}
return(p->mm);
}
void mm_exit( int rel) {
mmbs *t=NULL;
for(t=handle->next;t;t=t->next){
printf(MOUTWE,t->file,t->line,'E',(int)t->mm);
}
if(rel){
t=handle->next;
while(t){
handle->next=t->next;
free(t);
t=handle->next;
}
}
return;
}
void mm_free( void * p, char * file, int line) {
mmbs *now=handle,*pre=handle;
int nf=1;
if(p){
while(now){
if(now->mm==p){
pre->next=now->next;
free(now);
nf=0;
break;
}else{
pre=now;
now=now->next;
}
}
if(nf){
printf(MOUTWE,file,line,'W',(int)p);
}
}
return;
}
PROGRAMER: Wayne Huang
DATE: 2008.04.18
LICENCE: GPL v2.0
*/
#define MMALLOC(s) mm_malloc(s,__FILE__,__LINE__)
#define MFREE(p) mm_free(p,__FILE__,__LINE__)
#define MOUTWE "[%s:%d] {%c} 0x%x "
typedef struct mmbs mmbs;
struct mmbs {
mmbs *next;
char *file;
int line;
void *mm;
} ;
static mmbs mhandle = {NULL,0,0,0} ;
mmbs * handle =& mhandle;
void * mm_malloc(unsigned int s, char * file, int line);
void mm_free( void * p, char * file, int line);
void mm_exit( int rel);
void * mm_malloc(unsigned int s, char * file, int line) {
mmbs *p=malloc(sizeof(mmbs)+s);
mmbs *i=NULL;
if(p){
p->next=NULL;
p->file=file;p->line=line;
p->mm=&p[1];
for(i=handle;i->next;i=i->next);
i->next=p;
}
return(p->mm);
}
void mm_exit( int rel) {
mmbs *t=NULL;
for(t=handle->next;t;t=t->next){
printf(MOUTWE,t->file,t->line,'E',(int)t->mm);
}
if(rel){
t=handle->next;
while(t){
handle->next=t->next;
free(t);
t=handle->next;
}
}
return;
}
void mm_free( void * p, char * file, int line) {
mmbs *now=handle,*pre=handle;
int nf=1;
if(p){
while(now){
if(now->mm==p){
pre->next=now->next;
free(now);
nf=0;
break;
}else{
pre=now;
now=now->next;
}
}
if(nf){
printf(MOUTWE,file,line,'W',(int)p);
}
}
return;
}
用 MMALLOC(size); 替代你原先代码中的 malloc(size); MFREE(p); 替代你原来的 free(p); 然后在程序退出以前 执行函数 mm_exit(1); 就可以查看报告,并将泄漏的内存一并释放。如果需要在代码执行过程中查看内存的分配情况,可以执行 mm_exit(0); 来查看。
两个函数的不同之处在于,第一个会将未释放的内存释放掉。而第二个只是显示通过函数分配的内存情况。
对于程序执行过程中的输出 {W} 表示释放了一个没有被申请的内存。而 {E} 表示有内存泄漏的情况。在报告中会指明代码的具体位置等相关信息。
文外音:
原本在第一篇文章发表后,我曾记得有个人在我的文章留言里用C++写了一长串的代码,大概是我代码的两倍吧,好像还没贴完。来实现类似于我今天写的这点代码实现的功能,我粗略得看了下。其中用了符号的重载之类的。的确,我没有办法在不改变人们编程习惯的情况下用C语言实现更好的动态监测泄漏的代码。
我个人的观点是,能用10行代码解决的事情,绝对不要用100行代码来解决。
北斗星君(黄庠魁)