核心:什么时候有,在哪个地方
基本判断方式 1.htop/top;肉眼观察 htoptop 2.mtrace(1)CPU状态区域
(2)整体状态区域
(3)内存状态区域
(4)进程状态区域
(5)管理控制区域
使用方式:对原文件加上-g
gcc -g test.c export MALLOC_TRACE=a.log ./a.out unset MALLOC_TRACE #记得执行完后unset变量,否则可能运行其他命令可能覆盖log mtrace a.out a.log测试用例
#include运行结果 位置判断int main() { setenv("MALLOC_TRACE", "lxc.log", "1"); mtrace(); int *p = (int *)malloc(2 * sizeof(int)); return 0; }
1.文件调用自己的malloc和freemalloc没有free,new没有delete的地方
一般只适用于离线测试,在线测试不考虑
//每次你怀疑有内存泄漏,就if 1打开
#if 1
void* _malloc(size_t size,const char* file,int line){
void *p =malloc(size);//正常分配,p表示分配地址
// printf("malloc[+]:%p --->%s:%ld",p,file,line);
char buff[128] = {0};
sprintf(buff,"./mem/%p.mem",p);//把当前文件的地址作为文件名写入buff
FILE* fp = fopen(buff,"w");//打开文件
fprintf(fp,"[%s:%d]--->addr:%p,size:%ld",file,line,p,size);//写入文件
fflush(fp);
fclose(fp);
return p;
}
void* _free(void* p,const char* file,int line){
char buff[128] = {0};
sprintf(buff,"./mem/%p.mem",p);//故技重施,把p名字指向的文件地址给buff
//unlink应该就是减少一个文件指针,如果返回值<0说明这个文件本身就已经没有引用且被free过了
if(unlink(buff) < 0){
//执行unlink()函数会删除所给参数指定的文件
//如果不是1说明此文件还有其他链接对象,因此只对此文件的连接数进行减1操作
//若连接数为1,并且在此时没有任何进程打开该文件,此内容才会真正地被删除掉
//返回值:成功返回0,失败返回 -1
printf("double free.n",p);
return NULL;
}
free(p);
}
#define malloc(size) _malloc(size,__FILE__,__LINE__);
#define free(size) _free(size,__FILE__,__LINE__);
//__FILE__:宏定义,调用文件名;__LINE__:宏定义,调用行
//如果你的宏定义在你自己的函数声明之前,那就不能再你自己的代码里调用系统的malloc函数了
//你每次调用自己的,就会递归的调用被你改定义的新函数,就会死循环
//所以声明在实现后面,因为你调用的是改声明之前的同名函数
#endif
void func(void){
void *p1 = malloc(10);
void *p2 = malloc(20);//不free就删不掉文件
free(p1);
void *p3 = malloc(30);
free(p3);
return;
}
int main(){
func();
return 0;
}
//cd experment/Backend/memory_leak/singleMode
//gcc -o singleFile singleFile.c
// ./singleFile
运行结果
限制运行一次出一个这样的文件,对应程序里的p2
2.对malloc和free函数做一个hook(dlsym)你用了宏定义,这只适用于单个文件,因为加载时会有第三方so库,多文件不可以用
固定格式:定义一个与原函数同一回调类型的函数,做hook用
typedef void*(*malloc_t)(size_t size);//新的函数指针类型 malloc_t malloc_f = NULL;//一个该类型的指针变量 typedef void(*free_t)(void* p); free_t free_f = NULL;
对空函数指针初始化:
static void init_hook(){
if(malloc_f == NULL){
malloc_f = dlsym(RTLD_NEXT,"malloc");
}
if(free_f == NULL){
malloc_f = dlsym(RTLD_NEXT,"malloc");
}
}
init_hook()操作放在main函数入口的地方(第一行);不用的时候把第一行注释掉就行
#define DEBUG_MEMLEAK init_hook();
int main(){
DEBUG_MEMLEAK;
func();
return 0;
}
具体两个函数的覆写内容和前面完全一样,但是函数名和系统函数名一样了,里面调用的不再是系统函数,而是你定义的函数指针。
为了防止递归调用,还需要一个全局变量,确保只有第一次进入的时候执行你覆写的函数,其他的不会递归执行
保证你的函数不可重入
完整代码
#define _GNU_SOURCE #include#include #include #include //hook:定义一个和malloc同一回调类型的函数 typedef void*(*malloc_t)(size_t size);//函数指针 malloc_t malloc_f = NULL; typedef void(*free_t)(void* p); free_t free_f = NULL; int enable_hook_malloc = 1; int enable_hook_free = 1; //防止在你覆写的malloc函数里递归调用malloc函数(例如这里的fopen会调用系统的free),导致文件引用计数不一致 //因为有的调用malloc可能会会自己free,这样你再free就double void* malloc(size_t size){ if(enable_hook_malloc){ enable_hook_malloc = 0; void *p = malloc_f(size); void* caller = __builtin_return_address(0);//返回上一级调用点 //别打错了 //__FILE__和__LINE__只能在宏定义中,函数调用不能使用,所要用这个找到调用处, //0表示上一层,1表示上上层,以此类推 char buff[128] = {0}; sprintf(buff,"./mem/%p.mem",p); FILE* fp = fopen(buff,"w"); fprintf(fp,"[+%p]--->addr:%p,size:%ld",caller,p,size); fflush(fp); fclose(fp); enable_hook_malloc=1; }else{ return malloc_f(size); } return p; } void free(void* p){ if(enable_hook_free){ enable_hook_free=0; char buff[128] = {0}; sprintf(buff,"./mem/%p.mem",p); if(unlink(buff) < 0){ printf("double free.n",p); enable_hook_free=1; return; } free_f(p); enable_hook_free=1; }else{ free_f(p); } return; } static void init_hook(){ if(malloc_f == NULL){ malloc_f = dlsym(RTLD_NEXT,"malloc"); } if(free_f == NULL){ malloc_f = dlsym(RTLD_NEXT,"malloc"); } } #define DEBUG_MEMLEAK init_hook(); void func(void){ void *p1 = malloc(10); void *p2 = malloc(20); free(p1); void *p3 = malloc(30); free(p3); return; } int main(){ DEBUG_MEMLEAK; func(); return 0; } //cd experment/Backend/memory_leak/multiMode //gcc -o mem_hook mem_hook.c 这样就会undefied reference to dlsym //gcc -o mem_hook mem_hook.c -ldl // ./mem_hook //dlsym 报错,就查看怎么用这个:man dlsym
p3);
return;
}
int main(){
DEBUG_MEMLEAK;
func();
return 0;
}
//cd experment/Backend/memory_leak/multiMode
//gcc -o mem_hook mem_hook.c 这样就会undefied reference to dlsym
//gcc -o mem_hook mem_hook.c -ldl
// ./mem_hook
//dlsym 报错,就查看怎么用这个:man dlsym



