程序优化(一)

2018/07/17

1.c++实现一个不能被继承的类

一般我们都会把构造函数,析构函数设置为private,仿照单例模式来设计

class class1
{
	public:
		static class1 * getinstance(){
			return new class1();
		}
		static void deleteInstance(class1 *pInstace){
			delete pInstace;
		}
	private:
		class1(){};
		~class1(){};
}

但是在上面模式中,得到的实例都是在堆上,需要我们自己来释放,或者调用对应的函数。

考虑到这一局限,我们可以设计如下的一个类

template <typename T>
class MakeFinal
{
	friend T;
	private:
		MakeFinal(){};
		~MakeFinal(){};
}

class FinalClass2 : virtual public MakeFinal<FinalClass2>
{
	public:
		FinalClass2(){};
		~FinalClass2(){};
}

因为是友元类的关系,FinalClass2 可以调用MakeFinal的构造及析构函数

到那时继承自FinalClass2的类,如果要实例化,因为FinalClass2是虚继承,会跳过FinalClass2,而是直接调用MakeFinal的构造函数.但是此时已经 不可以调用MakeFinal的构造函数了。会导致编译错误.

2.如何自定义函数检测内存泄漏

gcc允许为函数设置__attribute__ ((constructor))和__attribute__ ((destructor))两种属性,顾名思义,就是将被修饰的函数作为构造函数或析构函数。 程序员可以通过类似下面的方式为函数设置这些属性:

void funcBeforeMain() __attribute__ ((constructor));
void funcAfterMain() __attribute__ ((destructor));

也可以放在函数名之前

void __attribute__ ((constructor)) funcBeforeMain();
void __attribute__ ((destructor)) funcAfterMain();

带有(constructor)属性的函数将在main()函数之前被执行,而带有(destructor)属性的函数将在main()退出时执行

leak_detector.h

#ifndef LEAK_DETECTOR_C_H
#define LEAK_DETECTOR_C_H

#pragma (report_mem_leak)

#define FILE_NAME_LENGTH 256  //用于存储malloc被调用的所在的文件名

#define CALL_DEPTH 10 //最大调用深度

#define TIME_LEN 26 //日期字符串的长度

#define OUTPUT_FILE "leak_info.txt" // 存储内存泄漏信息

#define malloc(size) mymalloc(size, __FILE__,__LINE__)

#define calloc(elements, size) mycalloc(elements ,__FILE__,__LINE__)

#define realloc (address, size) myrealloc(address, size, __FILE__,__LINE__)

#define free(mem_ref) myfree(mem_ref)

struct _MEM_TRACE_INFO{
	char ** traceInfo; 
	size_t size;
};

typedef struct  _MEM_TRACE_INFO MEM_TRACE_INFO;

struct _MEM_INFO{
	void *address ;
	unsigned int size ;
	char file_name[FILE_NAME_LENGTH];
	unsigned int line ;
	char allocTime[TIME_LEN];
	MEM_TRACE_INFO * traceInfo;
};

typedef struct _MEM_INFO MEM_INFO;

struct _MEM_LEAK {
	MEM_INFO mem_info;
	struct _MEM_LEAK  *next; 
};

typedef struct  _MEM_LEAK MEM_LEAK;

static void add(MEM_INFO alloc_info);
static void erase(void * address);
static void clear(void);

void *mymalloc(unsigned int, const char* ,unsigned int );
void *mycalloc(unsigned int ,unsigned int , const char* ,unsigned int );
void *myrealloc(void *,unsigned int , const char* ,unsigned int );
void *myfree( void * mem_ref);


static void add_mem_info(void*, unsigned int , const char* ,unsigned int , MEM_TRACE_INFO*);

static void remove_mem_info(void *mem_ref);

void report_mem_lead(void) __attribute__((destructor));

#endif

leak_detector.c

注意一下

  • #undef malloc
  • #undef calloc
  • #undef realloc
  • #undef free
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <time.h>
#include <execinfo.h>

#undef malloc
#undef calloc
#undef realloc
#undef free

static MEM_LEAK *ptr_start = NULL;
static MEM_LEAK *ptr_end = NULL; 

MEM_TRACE_INFO * getTrackInfo(){
	void * array[CALL_DEPTH];
	size_t size;
	size = backtrace(array,10);
	char ** trace = backtrace_symbols(array,size);
	MEM_TRACE_INFO * traceInfo = (MEM_TRACE_INFO *) malloc( sizeof(MEM_TRACE_INFO ));
	
	if(traceInfo == NULL){
		return NULL;
	}
	traceInfo ->size = size;
	traceInfo ->traceInfo = trace;
	return traceInfo;
}


void add(MEM_INFO alloc_info)
{
	printf("add new allocation info:%d\n", alloc_info.address);
	MEM_LEAK* mem_leak_info =NULL;
	mem_leak_info=(MEM_LEAK*) malloc(sizeof(MEM_LEAK));
	mem_leak_info->mem_info.address = alloc_info.address;
	mem_leak_info->mem_info.size = alloc_info.size;
	strcpy(mem_leak_info->mem_info.file_name,alloc_info.file_name);
	mem_leak_info->mem_info.line=alloc_info.line;
	mem_leak_info->mem_info.traceInfo= alloc_info.traceInfo;
	strncpy(mem_leak_info->mem_info.allocTime,alloc_info.allocTime,TIME_LEN);

	if(ptr_start == NULL){
		ptr_start  = mem_leak_info;
		ptr_end = ptr_start ;
	}else{
		ptr_end->next = mem_leak_info;
		ptr_end = ptr_end->next;
	}
}

void erase(void * address)
{
	MEM_LEAK *temp = ptr_start ;
	MEM_LEAK *pre;

	if(temp != NULL && temp->mem_info.address == address){
		ptr_start = temp->next;
		free(temp->mem_info.traceInfo);
		free(temp);
		return;
	}
	if(temp->next != NULL){
		pre = temp;
		temp = temp->next;
		for(; temp!= NULL; pre= temp,temp=temp->next)
		{
			if(temp->mem_info.address == address)
			{
				pre->next = temp ->next; 
				if(temp->next == NULL)
					ptr_end = pre;
				free(temp->mem_info.traceInfo);
				free(temp);
				break;
			}
		}
	}
}




void clear(){
	MEM_LEAK *temp = ptr_start;
	MEM_LEAK* alloc_info = ptr_start ;
	while(alloc_info != NULL)
	{
		alloc_info = alloc_info->next;
		free(temp->mem_info.traceInfo);
		free(temp);
		temp=alloc_info;
	}
}



void *mymalloc(unsigned int size , const char* file ,unsigned int line)
{
	void *ptr = malloc(size);
	if(ptr != NULL){
		MEM_TRACE_INFO *traceinfo = getTrackInfo();
		add_mem_info(ptr,size,file,line,traceinfo);
	}
	return ptr;
}

void *mycalloc(unsigned int elements ,unsigned int size , const char* file,unsigned int line)
{
	printf("calloc\n");
	unsigned total_size;
	void *ptr = calloc(elements,size);
	if(ptr != NULL)
	{
		MEM_TRACE_INFO* traceinfo = getTrackInfo();
		total_size = elements *size;
		add_mem_info(ptr,total_size,file,line,traceinfo);
	}
}

void *myrealloc(void * address ,unsigned int size , const char* file,unsigned int line)
{
	printf("realloc\n");
	unsigned total_size;
	void *ptr = realloc(address,size);
	if(ptr != NULL)
	{
		MEM_TRACE_INFO* traceinfo = getTrackInfo();
		remove_mem_info(address);
		add_mem_info(address,size,file,line,traceinfo);
	}
}


void *myfree( void * mem_ref)
{
	remove_mem_info(mem_ref);
	free(mem_ref);
}


void add_mem_info(void* mem_ref, unsigned int size, const char*file ,unsigned int line  , MEM_TRACE_INFO* traceinfo) 
{
	MEM_INFO mem_alloc_info;
	memset(&mem_alloc_info ,0 ,sizeof(mem_alloc_info));
	mem_alloc_info.address = mem_ref;
	mem_alloc_info.size = size;
	strcpy(mem_alloc_info.file_name, file);
	mem_alloc_info.line = line ;
	mem_alloc_info.traceInfo = traceinfo;
	time_t timeP = time(0);
	char* t = ctime(&timeP);
	strncpy(mem_alloc_info.allocTime ,t ,TIME_LEN);
	add(mem_alloc_info);
}

void remove_mem_info(void *mem_ref){
	erase(mem_ref);
}

void report_mem_lead(void) {
	unsigned int i ;
	printf("%s","mem_leak");
	unsigned short index ;
	MEM_LEAK * leak_info;

	FILE* fp_write = fopen(OUTPUT_FILE , "w");
	char info[1024];

	if( fp_write != NULL)
	{
		fprintf(fp_write ,"%s\n", "Memory Leak Summary");
		fprintf(fp_write ,"%s\n", "----------------------------------------");
		for( leak_info = ptr_start ; leak_info != NULL; leak_info = leak_info ->next)
		{
			fprintf(fp_write ,"address:%x\n",leak_info->mem_info.address);
			fprintf(fp_write ,"size   :%d bytes\n",leak_info->mem_info.size);
			fprintf(fp_write ,"file   :%s\n",leak_info->mem_info.file_name);
			fprintf(fp_write ,"line   :%d\n",leak_info->mem_info.line);
			fprintf(fp_write ,"Time   :%s\n",leak_info->mem_info.allocTime);
			fprintf(fp_write ,"traceInfo   :\n");
			for(i = 2 ;i < leak_info->mem_info.traceInfo->size-2;i++)
			{
				fprintf(fp_write ,"%s\n",leak_info->mem_info.traceInfo->traceInfo[i]);
			}
			fprintf(fp_write ,"%s\n","----------------------------------------");
		}
	}
	clear();
}

test.c

#include <stdio.h>
#include "leak_detector.h"

int main()
{
	char *p = NULL;
	p = (char*)malloc(4);
	free(p);
	p = (char*)malloc(5);
	p = (char*)malloc(6);
	return 0 ;
}

makefile

test:test.c leak_detector.h leak.so
gcc -o test test.c ./leak.so -rdynamic

leak.so:leak_detector.o
	gcc -shared -o leak.so leak_detector.o  -rdynamic

leak_detector.o:leak_detector.h leak_detector.c
	gcc -fpic -c leak_detector.c -rdynamic

clean:
	rm *.so *.o

检测结果如下:

Memory Leak Summary
----------------------------------------
address:14b6010
size   :5 bytes
file   :test.c
line   :12
Time   :Wed Jul 18 23:31:59 2018

traceInfo   :
./test(main+0x48) [0x400785]
----------------------------------------
address:14b6a60
size   :6 bytes
file   :test.c
line   :14
Time   :Wed Jul 18 23:31:59 2018

traceInfo   :
./test(main+0x60) [0x40079d]
----------------------------------------


扫描关注我

(转载本站文章请注明作者和出处 Undefined

Post Directory