手写内存泄漏组件


一、什么是内存泄漏

内存泄漏是指在程序运行过程中未释放已经分配的内存空间,导致这部分内存无法再被程序使用(也就是调用了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命令行工具可以将地址转化为行数,帮助我们定位到内存泄漏的地方

检测结果

在这里插入图片描述
这样就定位成功了。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值