功能:

用于检測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、源文件

#ifdef DETECT_MEMORY_LEAK
#define DETECT_MEMORY_LEAK_IMPL
#include "DetectMemoryLeak.h"
#include "stdio.h"
#include "string.h"
#include "malloc.h"

#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

c++程序内存泄露检測工具的更多相关文章

  1. Visual Studio内存泄露检測工具

    使用简单介绍     在敲代码的过程中.难免会遇到内存泄露的时候.这个时候假设手工查找内存泄露,不说方法没有通用的,就是真的要自己手工查找也是非常耗时间和精力的.诚然.我们能够借助一些工具,并且我们还 ...

  2. Linux C 编程内存泄露检測工具(二):memwatch

    Memwatch简单介绍 在三种检測工具其中,设置最简单的算是memwatch,和dmalloc一样,它能检測未释放的内存.同一段内存被释放多次.位址存取错误及不当使用未分配之内存区域.请往http: ...

  3. Visual C++ 2012/2013的内存溢出检測工具

    在过去,每次编写C/C++程序的时候,VLD差点儿是我的标配.有了它,就能够放心地敲代码,随时发现内存溢出. VLD最高可支持到Visual Studio 2012.不知道以后会不会支持Visual ...

  4. 内存泄露检測及cvClone造成的泄露

    调了几个小时,到最后发现内存泄露的原因是opencv的cvClone函数,採用cvCopy函数后,问题解决. vs2010使用vld进行内存泄露检測 (1) 下载vld工具 (2) 将D:\Progr ...

  5. C++内存泄露检測原理

    转自:http://hi.baidu.com/jasonlyy/item/9ca0cecf2c8f113a99b4981c 本文针对 linux 下的 C++ 程序的内存泄漏的检測方法及事实上现进行探 ...

  6. LeakCanary:简单粗暴的内存泄漏检測工具

    差点儿每一个程序猿在开发的过程中都会遇到内存泄漏.那么我们怎样检測到app是否哪里出现内存泄漏呢?square公司推出了一款简单粗暴的检測内存泄漏的工具-- LeakCanary 什么是内存泄漏? 内 ...

  7. vs2008内存泄露检測得到完美解决

    版权声明:原创文章.转载请注明出处.本博新地址www.iaccepted.net https://blog.csdn.net/IAccepted/article/details/27646679 Vi ...

  8. Android内存泄漏检測与MAT使用

    公司相关项目须要进行内存优化.所以整理了一些分析内存泄漏的知识以及工作分析过程. 本文中不会刻意的编写一个内存泄漏的程序,然后利用工具去分析它.而是通过介绍相关概念,来分析怎样寻找内存泄漏.并附上自己 ...

  9. Visual C++内存泄露检测—VLD工具使用说明[转]

    Visual C++内存泄露检测—VLD工具使用说明 一.        VLD工具概述 Visual Leak Detector(VLD)是一款用于Visual C++的免费的内存泄露检测工具.他的 ...

随机推荐

  1. 读Flask源代码学习Python--config原理

    读Flask源代码学习Python--config原理 个人学习笔记,水平有限.如果理解错误的地方,请大家指出来,谢谢!第一次写文章,发现好累--!. 起因   莫名其妙在第一份工作中使用了从来没有接 ...

  2. UltraISO制作U盘系统安装盘(图文教程)

    虽然现在的系统盘做的越来越傻瓜化,安装方法也非常多,但是仍然时常有朋友询问怎么安装系统,特别是没有刻录机或不想刻盘,又不懂硬盘安装的朋友,这里特别介绍一种用U盘来安装系统的方法,非量产,量产因U盘芯片 ...

  3. 分析java中clone()方法 (转载+修改)

    Java中的clone() 方法 java所有的类都是从java.lang.Object类继承而来的,而Object类提供下面的方法对对象进行复制. protected native Object c ...

  4. jQuery Pagination Plugin ajax分页控件

    <html> <body> <div id="datagrid"> </div> <div id="paginati ...

  5. uestc Palindromic String

    字符串hash因为如果一个字符串是回文串,那么正着做哈希和反着做哈希结果应该一样.于是我们先正反各做一边哈希.如果判断出来一个字符串是回文穿那么这个字符串的前半部分和后半部分的重数一定相同,于是当前位 ...

  6. applet部署,无需修改客户端设置。

    1  开发applet程序,编译成jar包 2  给jar包做数字签名: (1).用keytool生成密钥: keytool -genkey -keystore myapplet.keystore - ...

  7. $in的方法总结

    Ad.find({"_id":{$in:datas}},function(err,item){ if(err) console.log(err); //console.log(it ...

  8. NYOJ306 走迷宫(dfs+二分搜索)

    题目描写叙述 http://acm.nyist.net/JudgeOnline/problem.php?pid=306 Dr.Kong设计的机器人卡多非常爱玩.它经常偷偷跑出实验室,在某个游乐场玩之不 ...

  9. 达内TTS6.0课件oop_day05

  10. 教你爱上Blocks(闭包)

    传值 Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数.通过Blocks,源代码中就能使用匿名函数,即不带名称的函数.在我们 的工作中,命名占据了很大一部分,函数名,变量名,属性名, ...