C++程序内存泄露检测工具

  功能
   用于检測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)
#endif
void DumpLeakedMemoryInfo();
#endif//_DETECT_MEMORY_LEAK_H_
#endif//DETECT_MEMORY_LEAK

  2、源文件
#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

本文选自:http://www.spasvo.com/news/html/20141030112355.html

时间: 2024-10-05 04:53:10

C++程序内存泄露检测工具的相关文章

C程序内存泄露检测工具

今天给大家带来一款检测C程序内存泄露的一款实用工具--memwatch memwatch简介 MEMWATCH 由 Johan Lindh 编写,是一个开放源代码 C 语言内存错误检测工具.只要在代码中添加一个头文件并在 gcc 语句中定义了 MEMWATCH 之后,您就可以跟踪程序中的内存泄漏和错误了.MEMWATCH 支持 ANSI C,它提供结果日志记录,能检测双重释放(double-free).错误释放(erroneous free).没有释放的内存(unfreed memory).溢出

Unix下C程序内存泄露检测工具:valgrind的安装使用

Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Google-O'Reilly开源代码奖. Valgrind遵守GNU通用公共许可证条款,是一款自由软件. Valgrind的安装和使用 去官网www.valgrind.org下载最新版本的valgrind,我这里下载的是valgrind 3.11.0.tar.bz2. #tar xvf valgrind

自己实现简易的内存泄露检测工具VLD

有一个很著名的内存泄露检测工具Visual leak detected想必大家都不陌生,但今天我们可以自己写一个简易版的.哈哈,自己动手,丰衣足食有木有!!! 它的原理就是我们重载了操作符new和delete,当用new开辟空间的时候,就讲这块空间串到我们定义的结构体MEMNode形成的链表中,(这是老师的写法,在main程序结束时,用check_vld()函数检测有没有内存泄露)但我觉得,如果我们动态开辟了一个对象,在它的析构函数里用delete释放的话,这种方法就不太可行.因为析构函数只有到

内存泄露检测工具——LeakCanary

很简单:我们不是创建服务不是为了赚钱:我们赚钱是为了提供更好的服务.我们认为这才是做事的态度. 学习使用Java的同学都应该知道,Java的JVM给我们提供的垃圾回收机制是极为好用的.但是我们也很清楚,垃圾回收机制不是万能的,使用不当很容易造成内存泄露.之前我们也介绍过Java中常用的内存泄露检测工具MAT,目前Java程序最常用的内存分析工具应该是MAT(Memory Analyzer Tool),它是一个Eclipse插件,同时也有单独的RCP客户端. 不熟悉MAT的同学,或者对Java垃圾

vld,Bounds Checker,memwatch,mtrace,valgrind,debug_new几种内存泄露检测工具的比较

概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,这时就出现了内存泄漏.尽管优秀的编程实践可以确保最少的泄漏,但是根据经验,当使用大量的函数对相同的内存块进行处理时,很可能会出现内存泄漏. 内存泄露可以分为以下几类:1. 常发性内存泄漏.发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏.2. 偶发性内存泄漏.发生

vld(Visual Leak Detector) 内存泄露检测工具

初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复 杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题.内存泄漏是最常见的内存问题之一.内存泄漏如果不是很严重,在短时间内对程序不会有太大的 影响,这也使得内存泄漏问题有很强的隐蔽性,不容易被发现.然而不管内存泄漏多么轻微,当程序长时间运行时,其破坏力是惊人的,从性能下降到内存耗尽,甚 至会影响到其他程序的正常运行.另外内存问题的一个共同特点是,内存问题本身

Unix下C程序内存泄漏检测工具Valgrind安装与使用

Unix下C程序内存泄漏检测工具Valgrind安装与使用 Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Google-O'Reilly开源代码奖. Valgrind遵守GNU通用公共许可证条款,是一款自由软件. 官网 http://www.valgrind.org 下载与安装 #wget http://www.valgrind.org/downlo

Linux下C++内存泄露检测工具

下载安装:http://blog.csdn.net/wanglin754/article/details/7194145 下载地址:http://www.valgrind.org/downloads/current.html#current 安装valgrind tar jxvf valgrind-3.7.0.tar.bz2             注意这里的参数里加了j,表示有bz2属性 cd valgrind-3.7.0 ./configure make make install make

内存泄露检测工具

VS2008的内存泄露检测功能有限,使用也有些局限性.今天因工作时间紧迫,工程繁琐,我最终选择了VLD(Visual Leak Detector).这个工具使用起来十分简单,只需要: (1)下载安装vld.安装过程中可以发现vld安装向导提示关闭VS2008同时还将vld的头文件include目录路径.vld的库文件lib目录设置好了,简直太贴心.vld下载地址:http://vld.codeplex.com/ (2)在待检测的工程中添加头文件#include "vld.h"(我添加在