一、什么是内存泄漏
内存泄漏是指在程序运行过程中未释放已经分配的内存空间,导致这部分内存无法再被程序使用(也就是调用了malloc而没有使用free进行释放)。如果内存泄漏问题严重,会导致系统的可用内存逐渐减少,最终可能引发程序崩溃或者系统性能下降。
二、如何查看是否存在内存泄漏
使用top命令看内存情况只能推测存在泄露问题,但是并不能确定
而检查内存泄漏主要是两个方面:
1.是否存在内存泄漏
2.代码在哪一行出现了内存泄漏
main函数
void *p1=malloc(5);
void *p2=malloc(10);
void *p3=malloc(15);
free(p1);
free(p3);
日志记录
1.日志打印,在每次调用malloc和free的时候打印日志
void* nmalloc(size_t size){
void* p=malloc(size);
printf("nmalloc:%p,size:%ld\n",p,size);
return p;
}
void nfree(void* ptr){
printf("nfree:%p\n",ptr);
return free(ptr);
}
2.内存泄漏组件检查内存泄漏
小组件检测
对于自己写的程序进行检测
检测组件
void* nmalloc(size_t size,const char* filename,int line){
void* p=malloc(size);
if(flag){
char buff[128]={0};
snprintf(buff,128,"./mem/%p.mem",p);
FILE* fp=fopen(buff,"w");
if(!fp){
free(p);
return NULL;
}
fprintf(fp,"[+]%s:%d,addr:%p,size:%ld\n",filename,line,p,size);
fflush(fp);
fclose(fp);
}
//printf("nmalloc:%p,size:%ld\n",p,size);
return p;
}
void nfree(void* ptr){
//printf("nfree:%p\n",ptr);
if(flag){
char buff[128]={0};
snprintf(buff,128,"./mem/%p.mem",ptr);
if(unlink(buff)<0){
printf("double free:%p",ptr);
return;
}
}
return free(ptr);
}
#define malloc(size) nmalloc(size,__FILE__,__LINE__)
#define free(ptr) nfree(ptr)
检测结果
这可以检测到程序是否存在内存泄漏并且能够检测出代码是在哪一行出现了内存泄漏。
但是因为这是宏定义的方式,对于其他第三方库以及多文件的情况下不太适用
对于第三方库等代码问题
typedef void *(*malloc_t)(size_t size);
malloc_t malloc_f=NULL;
typedef void (*free_t)(void* ptr);
free_t free_f=NULL;
int enable_malloc=1;
int enable_free=1;
void *ConvertToELF(void *addr) {
Dl_info info;
struct link_map *link;
dladdr1(addr, &info, (void **)&link, RTLD_DL_LINKMAP);
return (void *)((size_t)addr - link->l_addr);
}
void* malloc(size_t size){
void* p=NULL;
if(enable_malloc){
enable_malloc=0;
p=malloc_f(size);
void* finder=__builtin_return_address(0);
char buff[128] = {0};
sprintf(buff, "./mem/%p.mem", p);
FILE *fp = fopen(buff, "w");
if (!fp) {
free(p);
return NULL;
}
//fprintf(fp, "[+]%p, addr: %p, size: %ld\n", caller, p, size);
fprintf(fp, "[+]%p, addr: %p, size: %ld\n", ConvertToELF(finder), p, size);
fflush(fp);
enable_malloc = 1;
} else {
p = malloc_f(size);
}
return p;
}
void free(void* ptr){
if (enable_free) {
enable_free = 0;
char buff[128] = {0};
snprintf(buff, 128, "./mem/%p.mem", ptr);
if (unlink(buff) < 0) {
printf("double free: %p", ptr);
return ;
}
free_f(ptr);
enable_free = 1;
} else {
free_f(ptr);
}
return ;
}
void init_hook(void){
if(!malloc_f){
malloc_f=(malloc_t)dlsym(RTLD_NEXT, "malloc");
}
if(!free_f){
free_f=(free_t)dlsym(RTLD_NEXT,"free");
}
}
void* finder=__builtin_return_address(0);是可以返回调用的地方,0是一级,之后依次递增。
void *ConvertToELF(void *addr) {
Dl_info info;
struct link_map *link;
dladdr1(addr, &info, (void **)&link, RTLD_DL_LINKMAP);
return (void *)((size_t)addr - link->l_addr);
}
这是求解相对地址路径的方法,addr是传进去的目标地址,link->l_addr是链接地址,程序在内存中的开始位置。
通过addr2line命令行工具可以将地址转化为行数,帮助我们定位到内存泄漏的地方
检测结果
这样就定位成功了。