:
用于检測c++程序的内存泄露。 原理: 事实上非常easy,就是通过函数的重载机制,捕获应用程序的new, new[] , delete , delete[], malloc,calloc,free等内存操作函数。 特点: 因为在检測的过程中,须要记录用户程序内存分配信息,所以本身必须进行内存动态分配。为了提高内存分配效率,程序实现了两个链表。 1、空暇链表,事实上就是一个简单的内存池 //定义一个结构,保存内存分配信息typedef struct _tagMemoryInfo{ ??? void* addr;????????? //保存分配的内存地址 ??? size_t size;???????? //内存大小 ??? _UL lineNum;????? //调用内存分配函数的行号 ??? char fileName[MAX_FILE_LEN];? //文件名 }MemoryInfo;//内存分配信息的链表结构,这里之所以定义为union类型,是为了省去next成员的开销
union FreeList{ ??? FreeList* next; ??? MemoryInfo data; }; 2、当前正在保存内存信息的链表 typedef struct _tagBusyList{ ??? _tagBusyList* next; ??? MemoryInfo* data; }BusyList; 不足: 1、仅仅是在vc2005上通过,没有在其它平台上过 2、不支持多线程(兴许有可能支持) 3、保存当前内存分配信息的链表,存在next字段的内存开销。 源码: 1、头文件 #ifdef DETECT_MEMORY_LEAK#ifndef _DETECT_MEMORY_LEAK_H_#define _DETECT_MEMORY_LEAK_H_typedef unsigned long _UL;void* __cdecl operator new(unsigned int size , _UL lineNum , const char* file);void* __cdecl operator new[](unsigned int size , _UL lineNum , const char* file);void __cdecl operator delete(void *p);void __cdecl operator delete [] (void *p);void __cdecl operator delete(void *p ,? _UL lineNum , const char* file);void __cdecl operator delete [] (void *p ,? _UL lineNum , const char* file);void* __cdecl _DebugMalloc(size_t size , _UL lineNum , const char* file);void* __cdecl _DebugCalloc(size_t num , size_t size , _UL lineNum , const char* file);void? __cdecl _DebugFree(void* addr);#ifndef DETECT_MEMORY_LEAK_IMPL#define new DEBUG_NEW#define DEBUG_NEW new(__LINE__ , __FILE__)#define malloc DEBUG_MALLOC#define DEBUG_MALLOC(x) _DebugMalloc(x , __LINE__ , __FILE__)#define calloc DEBUG_CALLOC#define DEBUG_CALLOC(x) _DebugCalloc(x , __LINE__ , __FILE__)#define free DEBUG_FREE#define DEBUG_FREE(x) _DebugFree(x)#endifvoid DumpLeakedMemoryInfo();#endif//_DETECT_MEMORY_LEAK_H_#endif//DETECT_MEMORY_LEAK2、源文件
#define MAX_FILE_LEN 128//须要实现的//1 将分配的内存信息写入文件//2 将释放的内存信息写入文件//3 将分配的内存信息都保存到内存中,提供一个接口将当前的内存泄露情况报告出去。//定义一个结构,保存内存分配信息typedef struct _tagMemoryInfo{ ??? void* addr;????????? //保存分配的内存地址??? size_t size;???????? //内存大小??? _UL lineNum;????? //调用内存分配函数的行号??? char fileName[MAX_FILE_LEN];? //文件名}MemoryInfo;//内存分配信息的链表结构,这里之所以定义为union类型,是为了省去next成员的开销union FreeList{ ??? FreeList* next;??? MemoryInfo data;};typedef struct _tagBusyList{ ??? _tagBusyList* next;??? MemoryInfo* data;}BusyList;//空暇链表的初始长度#define FREE_LIST_INIT_LEN 16//空暇链表的头指针static FreeList* g_freeList = NULL;//正在使用链表的头指针static BusyList* g_busyList = NULL;//内部使用函数的声明static void _CreateFreeList(int initLen);static void _ReleaseFreeList();static void* _GetFreeNode();static void* _GetBusyNode();static void _FreeNode(void* p);static void _WriteMemoryInfo(const MemoryInfo* pInfo , bool bAlloc);static void _StoreMemoryAllocInfo(void* addr , size_t size , _UL lineNum , const char* file);static void _StoreMemoryDeallocInfo(void* addr);void* __cdecl operator new(unsigned int size , _UL lineNum , const char* file){ ??? void* p = ::operator new(size);??? _StoreMemoryAllocInfo(p , size , lineNum , file);??? return p;??? //return 0;}void __cdecl operator delete(void* p){ ? _StoreMemoryDeallocInfo(p);}void __cdecl operator delete(void *p,? _UL lineNum , const char* file){ ??? lineNum;? file;??? _StoreMemoryDeallocInfo(p);}void* __cdecl operator new[](unsigned int size , _UL lineNum , const char* file){ ??? void* p = ::operator new(size);??? ??? _StoreMemoryAllocInfo(p , size , lineNum , file);??? ??? return p;???}void __cdecl operator delete [] (void *p){ ??? _StoreMemoryDeallocInfo(p);}void __cdecl operator delete [] (void *p ,? _UL lineNum , const char* file){ ? lineNum;? file;? _StoreMemoryDeallocInfo(p);}void* __cdecl _DebugMalloc(size_t size , _UL lineNum , const char* file){ ??? void* p = malloc(size);? _StoreMemoryAllocInfo(p , size , lineNum , file);? return p;}void* __cdecl _DebugCalloc(size_t num , size_t size , _UL lineNum , const char* file){ ? void* p = calloc(num , size);? _StoreMemoryAllocInfo(p , num * size , lineNum , file);? return p;}void? __cdecl _DebugFree(void* addr){?? _StoreMemoryDeallocInfo(addr);?}//创建一个空暇节点链表,生成一个内存池,用以记录内存分配信息。//这样当频繁分配内存的时候,不会由于检測本身的,影响应用程序的。void _CreateFreeList(int initLen){ ??? FreeList* p = (FreeList*)malloc(sizeof(FreeList) * initLen);??? g_freeList = p;??? for (int idx = 1; idx < initLen; ++idx)??? { ??????? p->next = p + idx;??????? p++;??? }??? p->next = NULL;}void* _GetFreeNode(){ ??? if ( g_freeList == NULL)??? { ??????? _CreateFreeList(FREE_LIST_INIT_LEN);??????? if ( NULL == g_freeList )??????? { ??????????? return NULL;??????? }??? }??? ??? FreeList* p = g_freeList;?????? g_freeList = g_freeList->next;??? return (void*)p;}void* _GetBusyNode(void* addr)
{ ? if ( g_busyList == NULL)? { ?? return NULL;? }? if ( NULL == g_busyList->next)? { ?? MemoryInfo* retNode = NULL;?? if (g_busyList->data->addr == addr)?? { ??? retNode = g_busyList->data;??????????? delete g_busyList;??? g_busyList = NULL;????????????? }? ?? return (void*)retNode;? }? BusyList* pre , *curr;? pre = curr = g_busyList;? while(curr)? { ?? if (curr->data->addr == addr)?? { ??? BusyList* tmp = curr;??? MemoryInfo* retNode = curr->data;??? pre->next = curr->next;??? free((void*)tmp);??? return (void*)retNode;?? }?? pre = curr;?? curr = curr->next;? }??? return NULL;}void _FreeNode(void* p){ ??? if ( NULL == p)??? { ??????? return;??? }??? FreeList* tmpNode = (FreeList*)p;??? tmpNode->next = g_freeList;??? g_freeList = tmpNode;}//保存内存分配信息void _StoreMemoryAllocInfo(void* addr , size_t size , _UL lineNum , const char* file){ ??? MemoryInfo* node = (MemoryInfo*)_GetFreeNode();??? if ( NULL == node )??? { ??????? return;??? }??? node->addr =addr;??? node->size = size;??? node->lineNum = lineNum;?? ??? size_t len = strlen(file);??? len = len >= MAX_FILE_LEN ? MAX_FILE_LEN - 1 : len;??? strncpy(node->fileName , file , len);? node->fileName[len] = '/0';??? //增加链表??? BusyList* busyNode = (BusyList*)malloc(sizeof(BusyList));??? busyNode->data = node;??? if ( g_busyList == NULL )??? { ??????? g_busyList = busyNode;??????? busyNode->next = NULL;??? }??? else??? { ??????? busyNode->next = g_busyList;??????? g_busyList = busyNode;??? }??? //写入文件??? _WriteMemoryInfo(node , true);}//保存内存分配信息void _StoreMemoryDeallocInfo(void* addr){ ? MemoryInfo* node = (MemoryInfo*)_GetBusyNode(addr);? if ( NULL == node )? { ?? return;? }? //写入文件? _WriteMemoryInfo(node , false);??? _FreeNode((void*)node);?}//写日志函数void _WriteMemoryInfo(const MemoryInfo* pInfo , bool bAlloc){ ??? if (pInfo != NULL)??? { ??????? FILE *fp = fopen("debugmemorylog.txt","a+");??????? if (!fp)??????????? return;??????? fprintf(fp,"%p:/t%s/t%d line %s %d bytes/n",pInfo->addr, pInfo->fileName, pInfo->lineNum /??????????? , (bAlloc ? "allocated" : "freed") , pInfo->size);??????? fflush(fp);??????? fclose(fp);??? }}//将泄露的内存信息写到磁盘void DumpLeakedMemoryInfo(){ ? FILE *fp = fopen("memoryleak.txt","a+");? if (!fp)?? return;? ? BusyList* p = g_busyList;? while (p)? { ?? BusyList* tmp = p;?? MemoryInfo* pInfo = tmp->data;?? if (pInfo != NULL)?? {?????? fprintf(fp,"%p:/t%s/t%d line leak %d bytes/n",pInfo->addr, pInfo->fileName, pInfo->lineNum , pInfo->size);????? }?? _FreeNode((void*)pInfo);?????? delete tmp;??? tmp = NULL;??? p = p->next;? }? fflush(fp);? fclose(fp);? //释放内存池资源给操作系统??? _ReleaseFreeList();}void _ReleaseFreeList(){ ??? while(g_freeList)? { ?? FreeList* tmp = g_freeList->next;?? delete g_freeList;?? g_freeList = tmp;??? }}#endif//DETECT_MEMORY_LEAK本文选自: