功能:

用于检測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. java文本编辑器5

    package peng_jun; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.* ...

  2. Prepare Python environment and install selenium.

    1, Install python and selenium. I use python 3.5, the following is the example 1.)    Python downloa ...

  3. 使用verilog实现4选1数据选择器的几种方法

    第一种方法module mux( d1, d2, d3, d4, se1, se2, dout ); input d1; input d2; input d3; input d4; input se1 ...

  4. Get Intellisense for .axml files in Visual Studio

    原文Get Intellisense for .axml files in Visual Studio So in order to get some intellisense support for ...

  5. ubuntu15.04下编译 libvirt

    很久没有编译 libvirt了. 工作需要,重新编译. [org_ref]: http://libvirt.org/compiling.html 很简单. 编译过程, 还是很多问题. 依赖包(给懒人参 ...

  6. 2.Visual Studio 2013中的默认快捷键

    这篇大致是IDE的使用技巧,常用的也就那么几个. 我自己用的最多的是注释.取消注释.格式调整.运行测试.开始调试.断开调试.重新开始调试.删除行ctrl+L.保存.全部保存.打开资源管理器.搜索等几个 ...

  7. JavaScript之共享onload

    我们知道,当我们将JS代码脚本放到<head></head>标签之间时,这是的js代码加载要先于DOM加载,而我们往往会在JS代码脚本中写一些获取DOM元素的代码,而此时的DO ...

  8. Deep Learning(深度学习)学习笔记整理系列之(一)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0  2013-0 ...

  9. Windows Server 2003 安装Sql Server 2005 问题处理

    安装途中遇到: 问题1.无法找到产品Microsoft SQL Server Native Client的安装程序包.请使用安装包sqlncli.msi的有效副本重新安装? 答:安装SQL Serve ...

  10. windows下设置/删除Tomcat的开机自启动

    绿色版tomcat在配置好Java环境以后直接运行bin下面的startup.bat就能够正常启动,但是在客户这里很多时候都 需要tomcat开机自动启动.下面简单介绍一如何在windows下面开机自 ...