轻松排查linux应用程序内存泄漏点

        指针是C语言的最重要的特色,用得好能写出优雅高效的代码,滥用了会成为烦恼的根源。当代码中大量使用指针,运行时内存分配,一不小心就会出现内存泄漏,因此,快速定位内存泄漏点,是高级c语言工程师必备技能。下面跟大家分享一个经过多年项目实践总结出来的定位内存泄漏的方法。

typedef struct 
{
	int malloc_size;
	int size;
	void **list;
} MALLOC_DEBUG;

MALLOC_DEBUG g_malloc_list={0,0,NULL};
pthread_mutex_t g_mutex_list=PTHREAD_MUTEX_INITIALIZER;


void find_empty(MALLOC_DEBUG *ls,void *ptr)
{
	int i=0;
	for(i=0; i<ls->malloc_size; i++){
		if(ls->list[i]==NULL){
			ls->list[i]=ptr;
			ls->size++;
			return;
		}
	}
	printf("find_empty()not find!\n");
}

void malloc_add(void *ptr)
{
	if(g_malloc_list.list==NULL || (g_malloc_list.size >= g_malloc_list.malloc_size)){
		int size=g_malloc_list.malloc_size + 512;
		if(size > 10000){
			printf("malloc_add()warning:More than 10000 records!\n");
			return;
		}
		void **buf=(void **)malloc(sizeof(void*) * size);
		if(buf){
			memset(buf,0,size * sizeof(void*));
			pthread_mutex_lock(&g_mutex_list);
			g_malloc_list.malloc_size=size;
			if(g_malloc_list.list){
				memcpy(buf,g_malloc_list.list,g_malloc_list.size * sizeof(void*));
				free(g_malloc_list.list);
			}

			g_malloc_list.list=buf;
			find_empty(&g_malloc_list,ptr);
			pthread_mutex_unlock(&g_mutex_list);
		}else{
			printf("malloc_add()malloc fail\n");
		}
	}else{
		pthread_mutex_lock(&g_mutex_list);
		find_empty(&g_malloc_list,ptr);
		pthread_mutex_unlock(&g_mutex_list);
	}
}

void malloc_free(void *ptr)
{
	int i=0;
	if(g_malloc_list.size > 0){
		for(i=0; i<g_malloc_list.malloc_size; i++){
			if(g_malloc_list.list[i] == ptr){
				pthread_mutex_lock(&g_mutex_list);
				g_malloc_list.list[i]=NULL;
				g_malloc_list.size--;
				pthread_mutex_unlock(&g_mutex_list);
				return;
			}
		}
	}
	printf("error:may be free multiple times of 0x%08x\n",(uint32_t)ptr);
}

void malloc_dump_and_destroy()
{
	if(g_malloc_list.size > 0){
		printf("The remaining %d malloc are not free:\n",g_malloc_list.size);
		for(int i=0; i<g_malloc_list.malloc_size; i++){
			if(g_malloc_list.list[i] != NULL){
				printf("0x%08x ",(uint32_t)g_malloc_list.list[i]);
			}
		}
		printf("\n");
	}else{
		printf("malloc and free times are equal\n");
	}

	if(g_malloc_list.list) free(g_malloc_list.list);
	g_malloc_list.list=NULL;
	g_malloc_list.malloc_size=0;
	g_malloc_list.size=0;
}

#define MALLOC_LOG_FILE "/tmp/malloc_log.txt"
uint8_t g_malloc_log=0;
FILE *g_fd_malloc_log=NULL;

/*malloc_set_log() for one thread only, please delete it after debugging*/
void malloc_set_log(uint8_t enable)
{
	g_malloc_log=enable;
	if(enable){
		g_fd_malloc_log=fopen(MALLOC_LOG_FILE,"a");
        if(g_fd_malloc_log){
		    fprintf(g_fd_malloc_log,">>>>>>>time:%u<<<<<<<\n\n",(uint32_t)time(NULL));
        }
	}else{
		if(g_fd_malloc_log){
			fprintf(g_fd_malloc_log,"\n\n");
			fclose(g_fd_malloc_log);
			g_fd_malloc_log=NULL;
			malloc_dump_and_destroy();
		}
	}
}

void *malloc_sg(size_t size,char *prompt)
{
	void *ptr=malloc(size);
	if(ptr==NULL){
		printf("%s malloc %d is fail!\n",prompt,size);
		fflush(stdout);
	}
	if(g_malloc_log && g_fd_malloc_log){
		fprintf(g_fd_malloc_log,"%s malloc %d ok:0x%08x\n",prompt,size,(uint32_t)ptr);
		fflush(g_fd_malloc_log);
		malloc_add(ptr);
	}
	return ptr;
}

void *realloc_sg(void *ptr,size_t size,char *prompt)
{
	void *ptr_new=realloc(ptr,size);
	if(ptr_new==NULL){
		printf("%s realloc %d at 0x%x is fail!\n",prompt,size,(uint32_t)ptr);
		fflush(stdout);
	}else{
		if(g_malloc_log && g_fd_malloc_log){
			fprintf(g_fd_malloc_log,"%s realloc %d at 0x%08x\n",prompt,size,(uint32_t)ptr);
			fprintf(g_fd_malloc_log,"%s realloc %d at 0x%08x new:0x%08x\n",prompt,size,(uint32_t)ptr,(uint32_t)ptr_new);
			fflush(g_fd_malloc_log);
			malloc_free(ptr);
			malloc_add(ptr_new);
		}
	}
	return ptr_new;
}

void free_sg(void *ptr,char *prompt)
{
	if(g_malloc_log && g_fd_malloc_log){
		fprintf(g_fd_malloc_log,"%s free 0x%08x\n",prompt,(uint32_t)ptr);
		fflush(g_fd_malloc_log);
		malloc_free(ptr);
	}
	free(ptr);
}

          使用void *malloc_sg(size_t size,char *prompt)分配内存,void free_sg(void *ptr,char *prompt)释放内存,都附带prompt参数,prompt参数用于记录分配、释放内存日记到文件,方便追踪内存泄漏点。void malloc_set_log(uint8_t enable)用于设置追踪的代码段起始点,enable=1是起点,enable=0是结束点,如有未释放内存,将打印未释放的内存地址,结合日记,可以找到内存泄漏点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值