嵌入式之内存泄漏定位篇

嵌入式之内存泄漏定位篇
在嵌入式开发中,经常会使用malloc,free分配释放堆内存,当malloc,free不配对使用时,就会导致内存一点点地泄露,直至堆内存泄露完,导致设备异常重启或死机现象。对于内存泄漏的情况,如果一开始不做预防,定位内存泄漏就会相当繁琐,定位也会很长,非常的耗时、耗力。
这里可通过malloc、free的第二次封装来预防内存泄漏,主要表现是分别记录不同地方调用malloc、free的次数,来判断malloc、free是否配对使用,如果不配对使用,可以帮助定位到哪个地方是不配对使用的,以此达到内存泄漏定位的效果。

以下将提供测试用例,效果描述:记录不同地方调用malloc、free的次数,每隔三秒将不同地方调用malloc、free的次数打印到终端,并文件的形式将信息保存到/tmp下。

编译后运行后,效果如下:
在这里插入图片描述
以下是malloc和free的第二次封装测试用例

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/prctl.h>
#include <sys/types.h>    
#include <sys/stat.h>  

#define Inf_Free(p)         MemFree(p) // free
#define Inf_Malloc(l)       MemMalloc(l, __FUNCTION__, __LINE__)  //  malloc
#define addrlistlen 1024*5
#define MAX_FILE_LEN (1024*1024)
#define MAX_MEM_LEN   256

static pthread_mutex_t g_alloc_mem_mutex = PTHREAD_MUTEX_INITIALIZER;//静态创建
static int memory_check = 0;

typedef struct StatisticalMemoryNode
{
    char szFile[MAX_MEM_LEN];
    unsigned int iLine;
    int statisticalMemoryTatolcounts;
    int statisticalMemoryReleaseTatolcounts;
    long addrList[addrlistlen];
    int addrListCounts;
    int addrListNext;
    struct StatisticalMemoryNode* next;
}StatisticalMemoryNode_S;

static StatisticalMemoryNode_S *g_pStatisticaMemHead = NULL;




int StatisticalMemoryApplication(const char *str_string, int lines, void *addr)
{
	if(0 == memory_check)
	{
		return 0;
	}
	
	int malloc_sign = 0,found = 0;
	int temp_add = 0 ,i;
	pthread_mutex_lock(&g_alloc_mem_mutex);
	StatisticalMemoryNode_S *temp = g_pStatisticaMemHead;

	while(temp)
	{
		if(lines == temp->iLine && strcmp(temp->szFile,str_string) == 0)
		{
			malloc_sign =1;
			break;
		}
		temp = temp->next;
	}

	if(malloc_sign != 1)
	{
		StatisticalMemoryNode_S *node = (StatisticalMemoryNode_S *)malloc(sizeof(StatisticalMemoryNode_S));
		strncpy(node->szFile , str_string , sizeof(node->szFile));
		node->iLine = lines;
		node->next = NULL;
		node->statisticalMemoryTatolcounts = 1;
		node->statisticalMemoryReleaseTatolcounts = 0;
		node->addrListNext = 0;
		memset(node->addrList , 0 , sizeof(node->addrList));
		node->addrList[node->addrListNext] = (long)addr;
		node->addrListCounts=1;
		if(!g_pStatisticaMemHead)
		{
			g_pStatisticaMemHead = node;
		}
		else
		{
			node->next = g_pStatisticaMemHead;
			g_pStatisticaMemHead = node;
		}
	}
	else
	{

		temp_add = temp->addrListNext;
		for(i = 0 ; i < addrlistlen ; i++ )
		{
			temp_add = temp_add % addrlistlen;
			if(temp->addrList[temp_add] == 0)
			{
				found = 1;
				temp->addrListNext = temp_add;
				break;
			}
			temp_add++;
		}
		
		if(found)
		{
			temp->statisticalMemoryTatolcounts++;
			temp->addrListCounts++;
			temp->addrList[temp->addrListNext] = (long)addr;
		}
	}
	pthread_mutex_unlock(&g_alloc_mem_mutex);
	return 0;
}

int StatisticalMemoryRelease(const char *str_string, int lines, void *addr)
{
	if(0 == memory_check)
	{
		return 0;
	}
	int i,found = 0;
	pthread_mutex_lock(&g_alloc_mem_mutex);
	StatisticalMemoryNode_S *temp = g_pStatisticaMemHead;
	while(temp)
	{	
	
		for(i=0;i<addrlistlen;i++)
		{
			if(temp->addrList[i] == (long)addr)
			{
				found =1;
				break;
			}
		}

		if(found)
			break;
		temp = temp->next;
	}
	
	if(found)
	{
		temp->statisticalMemoryReleaseTatolcounts++;
		temp->addrListCounts--;
		temp->addrList[temp->addrListNext] = 0;
	}
	pthread_mutex_unlock(&g_alloc_mem_mutex);
	return 0;
}

void* MemMalloc(int ilen, const char* pszFile, int iLine)
{
    if(0 == memory_check)
    {
        return malloc(ilen);
    }
    else
    {
    	void *addr = malloc(ilen);
		StatisticalMemoryApplication(pszFile, iLine, addr);
		return addr;
    }
}

void MemFree(void* pBuf)
{
    if (pBuf == NULL) return;
    if(0 == memory_check)
    {
        free(pBuf);
    }
    else
    {
       free(pBuf);
       StatisticalMemoryRelease(NULL, 0, pBuf);
    }
}

void *Thread_Mem_Debug(void)
{
	prctl(PR_SET_NAME, "Thread_Mem_Debug", 0, 0, 0);
    pthread_detach(pthread_self());
	while(1)
	{
		if (g_pStatisticaMemHead == NULL)
		return 0;
		pthread_mutex_lock(&g_alloc_mem_mutex);
		char filePath[256] = {0};
		sprintf(filePath,"/tmp/statisticalMemory_%s", "app");
		int clearFlag = 0;
		FILE *fp = NULL;
		if (access(filePath, F_OK )  == 0)
		{
			struct stat filestat;
			stat(filePath, &filestat);

			if (filestat.st_size > MAX_FILE_LEN)
			{
				clearFlag = 1;
			}
		}

		fp = fopen(filePath, (clearFlag == 0) ? "a+" : "w+");
		if (NULL == fp)
		{
			pthread_mutex_unlock(&g_alloc_mem_mutex);
			printf("fopen error! %s %d\n",__FUNCTION__,__LINE__);
			return NULL;
		}

		char buffer[1024] = {0};

		time_t currentTime;
		currentTime = time((time_t*)NULL);
		struct tm tmTmp;
		gmtime_r(&currentTime, &tmTmp);

		sprintf(buffer, "\n********************%d.%d.%d  %d:%d:%d*********************\n",\
			tmTmp.tm_year+1900, tmTmp.tm_mon+1, tmTmp.tm_mday, tmTmp.tm_hour+8, tmTmp.tm_min, tmTmp.tm_sec);
		printf("%s\n",buffer);
		fwrite(buffer, strlen(buffer), 1, fp);

		StatisticalMemoryNode_S *tmp = g_pStatisticaMemHead;
		while(tmp)
		{
			memset(buffer, 0, 1024);
			sprintf(buffer,"[%s-%u] statisticalMemoryTatolcounts(%d) - ReleaseTatolcounts(%d) = %d\r\n",
				tmp->szFile, tmp->iLine, tmp->statisticalMemoryTatolcounts, tmp->statisticalMemoryReleaseTatolcounts, tmp->addrListCounts);
			printf("%s\n",buffer);
			fwrite(buffer, strlen(buffer), 1, fp);

			tmp = tmp->next;
		}
		fclose(fp);
		pthread_mutex_unlock(&g_alloc_mem_mutex);
    
		sleep(3);
	}
	return 0;
}

void *Thread_Mem_Test2(void)
{
	prctl(PR_SET_NAME, "Thread_Mem_Test2", 0, 0, 0);
    pthread_detach(pthread_self());
	while(1)
	{
		char *p = (char *)Inf_Malloc(12);
		Inf_Free(p);
		p=NULL;
		sleep(2);
	}
	return 0;
}

void *Thread_Mem_Test1(void)
{
	prctl(PR_SET_NAME, "Thread_Mem_Test1", 0, 0, 0);
    pthread_detach(pthread_self());
	while(1)
	{
		char *p = (char *)Inf_Malloc(12);
		Inf_Free(p);
		p=NULL;
		sleep(2);
	}
	return 0;
}

int main()
{
	//pthread_mutex_init(&g_alloc_mem_mutex, NULL);//动态创建
	memory_check =1;//
	pthread_t id[3] = {-1};	

	if(0 != pthread_create(&id[0], NULL, (void *)Thread_Mem_Debug, NULL))
	{
		printf("Thread_Mem_Debug debug print create failed!\n");
		return -1;
	}	
	
	if(0 != pthread_create(&id[1], NULL, (void *)Thread_Mem_Test2, NULL))
	{
		printf("Thread_Mem_Test2 debug print create failed!\n");
		return -1;
	}
	
	if(0 != pthread_create(&id[2], NULL, (void *)Thread_Mem_Test1, NULL))
	{
		printf("Thread_Mem_Test1 debug print create failed!\n");
		return -1;
	}
	
	while(1)
	{
		char *p = (char *)Inf_Malloc(12);
		Inf_Free(p);
		p=NULL;
		sleep(2);
	}
	
	return 0;
}

总结:测试用例不仅适用于maloc,free的内存泄漏定位,也适用于open close等描述符,比如文件描述符、套接字描述符等泄漏定位的操作。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值