内存泄漏
核心:什么时候有,在哪个地方
基本判断方式
1.htop/top;肉眼观察
htop
(1)CPU状态区域 (2)整体状态区域 (3)内存状态区域 (4)进程状态区域 (5)管理控制区域
top
2.mtrace
使用方式:对原文件加上-g
gcc -g test.c
export MALLOC_TRACE=a.log
./a.out
unset MALLOC_TRACE
mtrace a.out a.log
测试用例
#include <stdio.h>
int main()
{
setenv("MALLOC_TRACE", "lxc.log", "1");
mtrace();
int *p = (int *)malloc(2 * sizeof(int));
return 0;
}
运行结果
位置判断
malloc没有free,new没有delete的地方
一般只适用于离线测试,在线测试不考虑
1.文件调用自己的malloc和free
#if 1
void* _malloc(size_t size,const char* file,int line){
void *p =malloc(size);
char buff[128] = {0};
sprintf(buff,"./mem/%p.mem",p);
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);
if(unlink(buff) < 0){
printf("double free.\n",p);
return NULL;
}
free(p);
}
#define malloc(size) _malloc(size,__FILE__,__LINE__);
#define free(size) _free(size,__FILE__,__LINE__);
#endif
void func(void){
void *p1 = malloc(10);
void *p2 = malloc(20);
free(p1);
void *p3 = malloc(30);
free(p3);
return;
}
int main(){
func();
return 0;
}
运行结果
运行一次出一个这样的文件,对应程序里的p2
限制
你用了宏定义,这只适用于单个文件,因为加载时会有第三方so库,多文件不可以用
2.对malloc和free函数做一个hook(dlsym)
固定格式:定义一个与原函数同一回调类型的函数,做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<dlfcn.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
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;
void* malloc(size_t size){
if(enable_hook_malloc){
enable_hook_malloc = 0;
void *p = malloc_f(size);
void* caller = __builtin_return_address(0);
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;
}
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
|