Reference: https://blog.csdn.net/u014023615/article/details/39551191

Reference: https://blog.csdn.net/u014023615/article/details/39551191

实现类:

DumpMemoryLeaks.h

/**

* @file DumpMemoryLeaks.h

* @brief 跟踪内存分配并定时输到文件,以协助检查有无内存泄漏

*

* 修订记录

* @author jack3z

* @version 1.00

* @date 2014-05-18

*

*/

#ifndef DUMPMEMORYLEAKS_H

#define DUMPMEMORYLEAKS_H

#ifdef __linux__

# include <pthread.h>

#else

# include <Windows.h>

#endif

#include <stdio.h>

#include <stdlib.h>

#include <malloc.h>

#include <time.h>

#include <string>

#include <map>

#include <list>

#include <assert.h>

#ifndef DUMP_MEM_REPORT_FREQUENCY

//# define DUMP_MEM_REPORT_FREQUENCY (30*60) //每隔30分钟输出一次内存分配情况

//# define DUMP_MEM_REPORT_FREQUENCY 60 //每隔一分钟输出一次内存分配情况

# define DUMP_MEM_REPORT_FREQUENCY 10 //测试时,10秒输出一次内存分配情况

#endif

struct StMemAllocRec

{

void* addr;

size_t nSize;

};

class CAllocLocalInfo

{

public:

CAllocLocalInfo()

{

m_nLine = -1;

}

std::string m_strFile;

int m_nLine;

bool operator<(const CAllocLocalInfo& other) const

{

return m_strFile < other.m_strFile || (m_strFile==other.m_strFile && m_nLine < other.m_nLine);

}

};

class CDumpMemoryLeaks

{

private:

CDumpMemoryLeaks(void);

~CDumpMemoryLeaks(void);

public:

static CDumpMemoryLeaks& GetInstance()

{

static CDumpMemoryLeaks inst;

return inst;

}

void Init();

void AddTrack(void* addr, size_t asize, const char *fname, int lnum);

void RemoveTrack(void* addr);

protected:

bool IsTheTime2Dump()

{

return m_timeDump < time(NULL);

}

void ResetDumpTime()

{

m_timeDump = time(NULL) + DUMP_MEM_REPORT_FREQUENCY;

}

void Dump();

void lock()

{

#ifdef __linux__

pthread_mutex_lock(&m_mtx);

#else

EnterCriticalSection(&m_mtx);

#endif

}

void unlock()

{

#ifdef __linux__

pthread_mutex_unlock(&m_mtx);

#else

LeaveCriticalSection(&m_mtx);

#endif

}

protected:

bool m_bInit;

FILE* m_fpDumpFile;

std::string m_strDumpFile;

std::map< CAllocLocalInfo, std::list<StMemAllocRec> > m_mapAllocRec;

std::map<void *,CAllocLocalInfo> m_mapAddr2AllocLocal;

time_t m_timeDump;

std::string m_strMsg;

char m_szBuf[1024];

#ifdef __linux__

pthread_mutex_t m_mtx;

#else

CRITICAL_SECTION m_mtx;

#endif

};

//#ifdef DEBUG_REPORT_NEW_ALLOC

inline void * operator new(size_t size, const char* file, const size_t line)

{

void *ptr = (void*)malloc(size);

CDumpMemoryLeaks::GetInstance().AddTrack(ptr, size, file, line);

return(ptr);

}

inline void * operator new [](size_t size, const char* file, const size_t line)

{

void *ptr = (void*)malloc(size);

CDumpMemoryLeaks::GetInstance().AddTrack(ptr, size, file, line);

return ptr;

}

inline void operator delete(void *p)

{

CDumpMemoryLeaks::GetInstance().RemoveTrack(p);

free(p);

}

inline void operator delete(void *p, size_t size)

{

CDumpMemoryLeaks::GetInstance().RemoveTrack(p);

free(p);

}

inline void operator delete(void *p, const char* file, const size_t line)

{

CDumpMemoryLeaks::GetInstance().RemoveTrack(p);

free(p);

}

inline void operator delete [](void *p)

{

CDumpMemoryLeaks::GetInstance().RemoveTrack(p);

free(p);

}

inline void operator delete [](void *p, size_t size)

{

CDumpMemoryLeaks::GetInstance().RemoveTrack(p);

free(p);

}

inline void operator delete [](void *p, const char* file, const size_t line)

{

CDumpMemoryLeaks::GetInstance().RemoveTrack(p);

free(p);

}

#define malloc(s) ((void*)new unsigned char[s])

#define free(p) (delete [] (char*)(p));

#define new new(__FILE__, __LINE__) //1st parameter:size is not needed, passed by the compiler

//#endif

#endif

DumpMemoryLeaks.cpp

#include "DumpMemoryLeaks.h"

#ifndef localtime_r

#if _MSC_VER >= 1400

//Visual C++ 2005 以及更高版本

# define localtime_r(_Time_ptr,_Tm_ptr) (localtime_s((_Tm_ptr),(_Time_ptr)) == 0 ? (_Tm_ptr) : NULL)

#else

# define localtime_r(_Time_ptr,_Tm_ptr) ( *(_Tm_ptr) = *localtime(_Time_ptr), (_Tm_ptr))

#endif //#if _MSC_VER >= 1500

#endif //#ifndef localtime_r

#ifdef _MSC_VER

# ifndef snprintf

# define snprintf _snprintf

# endif//snprintf

#endif //_MSC_VER

CDumpMemoryLeaks::CDumpMemoryLeaks(void)

{

m_bInit = false;

m_fpDumpFile = NULL;

m_timeDump = NULL;

memset(m_szBuf,0,sizeof(m_szBuf));

#ifdef __linux__

pthread_mutexattr_t mattr;

pthread_mutexattr_init(&mattr);

pthread_mutexattr_settype(&mattr , PTHREAD_MUTEX_RECURSIVE);

pthread_mutex_init(&m_mtx,&mattr);

#else

InitializeCriticalSection(&m_mtx);

#endif

}

CDumpMemoryLeaks::~CDumpMemoryLeaks(void)

{

if (m_fpDumpFile)

{

fclose(m_fpDumpFile);

m_fpDumpFile = NULL;

}

#ifdef __linux__

pthread_mutex_destroy(&m_mtx);

#else

DeleteCriticalSection(&m_mtx);

#endif

}

void CDumpMemoryLeaks::Init()

{

lock();

if (!m_bInit)

{

ResetDumpTime();

m_bInit = true;

}

unlock();

}

void CDumpMemoryLeaks::AddTrack(void* addr, size_t asize, const char *fname, int lnum)

{

lock();

if (!m_bInit)

{

Init();

}

CAllocLocalInfo alloc_local;

alloc_local.m_strFile = fname;

alloc_local.m_nLine = lnum;

StMemAllocRec mem_alloc_rec;

mem_alloc_rec.addr = addr;

mem_alloc_rec.nSize = asize;

m_mapAllocRec[alloc_local].push_back(mem_alloc_rec);

m_mapAddr2AllocLocal[addr] = alloc_local;

if (IsTheTime2Dump())

{

Dump();

ResetDumpTime();

}

unlock();

}

void CDumpMemoryLeaks::RemoveTrack(void* addr)

{

lock();

if (!m_bInit)

{

Init();

}

bool bRemoveSuccess = false;

std::map<void *, CAllocLocalInfo>::iterator itorAddr2AllocLocal = m_mapAddr2AllocLocal.find(addr);

if (itorAddr2AllocLocal == m_mapAddr2AllocLocal.end())

{

unlock();

return;

}

else

{

std::map< CAllocLocalInfo, std::list<StMemAllocRec> >::iterator itorAllocRec = m_mapAllocRec.find(itorAddr2AllocLocal->second);

assert(itorAllocRec != m_mapAllocRec.end());

std::list<StMemAllocRec>& listAllocRec = itorAllocRec->second;

for (std::list<StMemAllocRec>::iterator itor = listAllocRec.begin();

itor != listAllocRec.end();

++itor)

{

if ((*itor).addr == addr)

{

listAllocRec.erase(itor);

bRemoveSuccess = true;

break;

}

}

if (listAllocRec.empty())

{

m_mapAllocRec.erase(itorAllocRec);

m_mapAddr2AllocLocal.erase(itorAddr2AllocLocal);

}

}

assert(bRemoveSuccess);

if (IsTheTime2Dump())

{

Dump();

ResetDumpTime();

}

unlock();

}

void CDumpMemoryLeaks::Dump()

{

time_t timeNow = time(NULL);

struct tm tmNow;

if (NULL == localtime_r(&timeNow,&tmNow))

{

assert(false);

}

if (m_strMsg.empty())

{//生成信息

size_t nTotalAlloc = 0;

std::list<CAllocLocalInfo> listLocal;//按内存大到小排序

std::map<CAllocLocalInfo,size_t> mapLocal2Size;

for (std::map< CAllocLocalInfo, std::list<StMemAllocRec> >::iterator itor = m_mapAllocRec.begin();

itor != m_mapAllocRec.end();

++itor)

{

const CAllocLocalInfo& local = itor->first;

std::list<StMemAllocRec>& listAllocRec = itor->second;

for (std::list<StMemAllocRec>::iterator itor = listAllocRec.begin();

itor != listAllocRec.end();

++itor)

{

nTotalAlloc += itor->nSize;

mapLocal2Size[local] += itor->nSize;

}

}

for (std::map<CAllocLocalInfo,size_t>::iterator itor = mapLocal2Size.begin();

itor != mapLocal2Size.end();

++itor)

{

std::list<CAllocLocalInfo>::iterator itorLocalList = listLocal.begin();

for (;

itorLocalList != listLocal.end();

++itorLocalList)

{

if (itor->second >= mapLocal2Size[*itorLocalList])

{

break;

}

}

listLocal.insert(itorLocalList,itor->first);

}

snprintf(m_szBuf,sizeof(m_szBuf)-1,"Total unfree:%lu \n",(unsigned long)nTotalAlloc);

m_strMsg += "\n";

m_strMsg += m_szBuf;

m_strMsg += "--------------------------------------------------------------------------\n";

snprintf(m_szBuf,sizeof(m_szBuf)-1,

"Time: %04u-%02u-%02u %02u:%02u:%02u\n\n",

tmNow.tm_year + 1900,

tmNow.tm_mon + 1,

tmNow.tm_mday,

tmNow.tm_hour,

tmNow.tm_min,

tmNow.tm_sec

);

m_strMsg += m_szBuf;

double dTotalReciprocal = 1.0/(double)nTotalAlloc;

for (std::list<CAllocLocalInfo>::iterator itorLocalList = listLocal.begin();

itorLocalList != listLocal.end();

++itorLocalList)

{

size_t nSize = mapLocal2Size[*itorLocalList];

snprintf(m_szBuf,sizeof(m_szBuf)-1,

"%s:line %d, unfreed size:%lu, percentage:%lf %%; alloc times:%lu\n",

itorLocalList->m_strFile.c_str(),

itorLocalList->m_nLine,

nSize,

nSize*dTotalReciprocal*100,

(unsigned long)m_mapAllocRec[*itorLocalList].size()

);

m_strMsg += m_szBuf;

}

m_strMsg += "--------------------------------------------------------------------------\n";

}

//////////////////////////////////////////////////////////////////////////

//文件操作:打开文件,分割文件并写入

snprintf(m_szBuf,sizeof(m_szBuf)-1,

"MemoryAllocReport_%04u-%02u-%02u.txt",

tmNow.tm_year + 1900,

tmNow.tm_mon + 1,

tmNow.tm_mday

);

if (!m_fpDumpFile)

{

m_fpDumpFile = fopen(m_szBuf,"a");

m_strDumpFile = m_szBuf;

fprintf(m_fpDumpFile, "\n\n---------------- DumpMemoryLeaks begin! ----------------\n");

}

else

{

if (m_strDumpFile != m_szBuf)

{

fclose(m_fpDumpFile);

m_fpDumpFile = fopen(m_szBuf,"w");

m_strDumpFile = m_szBuf;

}

}

fwrite(m_strMsg.c_str(),m_strMsg.length(),1,m_fpDumpFile);

//文件操作结束

//////////////////////////////////////////////////////////////////////////

m_strMsg.clear();

}

实现方法:把文件保存到项目源文件目录下并在全局头文件添加# include "DumpMemoryLeaks.h"

如在win32工程中的stdafx.h文件内添加:

#ifdef _DEBUG

# include "DumpMemoryLeaks.h"

#endif // _DEBUG

测试:

// DbgMemLeak.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include <list>

using namespace std;

class A

{

public:

A()

{

m_i = 9;

}

~A()

{

if (m_i != 9)

{

assert(false);

}

m_i = 1;

}

int m_i;

};

class B

{

public:

B()

{

printf("new B instance %p \n", this);

}

~B()

{

printf("delete B instance %p \n", this);

}

};

int main(int argc, _TCHAR* argv[])

{

/*

{//测试构造和析构

B* pB = new B();

delete pB;

Sleep(3*1000);//方便观察终端输出内容

}

*/

{//测试数组构造和析构

B* pArray = new B[4];

delete[] pArray;

pArray = NULL;

Sleep(3*1000);//方便观察终端输出内容

}

/*

{//测试new和delete基础类型数组

char* pChArr = new char[1024];

delete pChArr;

}

*/

//模拟内存泄漏

for (int i = 0; i < 60*30*10; ++i)

{

A* p = new A ;

Sleep(100);

if (i%2 == 0)

{

delete p;

}

}

for (int i = 0; ; ++i)

{

A* p = new A ;

Sleep(1);

if (i%4 == 0)

{

delete p;

}

}

return 0;

}

---------------------

本文来自 jack3z 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/u014023615/article/details/39551191?utm_source=copy

C++:重载全局new/delete实现跨平台多线程内存检测的更多相关文章

  1. 重载全局new/delete实现内存检测

    下面介绍用重载new/delete运算符的方式来实现一个简单的内存泄露检测工具,基本思想是重载全局new/delete运算符,被检测代码调用new和delete运算符时就会调用重载过的operator ...

  2. 【ThinkingInC++】64、重载new和delete,来模仿内存的分配

    /** * 书本:[ThinkingInC++] * 功能:重载new和delete.来模仿内存的分配 * 时间:2014年10月5日14:30:11 * 作者:cutter_point */ #in ...

  3. 重载operator new delete函数

    可以重载global的operator new delete 函数,细节如下: MyNewDelete.h #pragma once #include <stdlib.h> #includ ...

  4. ZT c++ 中的重载全局new,delete

    c++ 中的重载全局new,delete 分类: c++ 2010-08-06 10:31 116人阅读 评论(1) 收藏 举报 deletec++file编译器语言工作 最近做一个小项目,对c++又 ...

  5. C++ 重载new和delete操作符

    原因: C++标准库提供的new和delete操作符,是一个通用实现,未针对具体对象做具体分析 存在分配器速度慢.小型对象空间浪费严重等问题,不适用于对效率和内存有限制的应用场景   好处: 灵活的内 ...

  6. 重载new和delete来检测内存泄漏

    重载new和delete来检测内存泄漏 1. 简述 内存泄漏属于资源泄漏的一种,百度百科将内存泄漏分为四种:常发性内存泄漏.偶发性内存泄漏.一次性内存泄漏和隐式内存泄漏.    常发性指:内存泄漏的代 ...

  7. 重载new和delete

    当我们创建一个new表达式时,会发生两件事.首先使用operator new()分配内存,然后调用构造函数.在delete表达式里,调用了析构函数,然后使用operator delete()释放内存. ...

  8. C++中基于Crt的内存泄漏检测(重载new和delete,记录在Map里)

    尽管这个概念已经让人说滥了 ,还是想简单记录一下, 以备以后查询. #ifdef _DEBUG#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FIL ...

  9. c/c++ 重载new,delete运算符 placement new

    重载new,delete运算符 new,delete在c++中也被归为运算符,所以可以重载它们. new的行为: 先开辟内存空间 再调用类的构造函数 开辟内存空间的部分,可以被重载. delete的行 ...

随机推荐

  1. POJ 2409 Let it Bead【Polya定理】(模板题)

    <题目链接> 题目大意:用k种颜色对n个珠子构成的环上色,旋转.翻转后相同的只算一种,求不等价的着色方案数. 解题分析: 对于这种等价计数问题,可以用polay定理来解决,本题是一道pol ...

  2. 爬虫之Resquests模块的使用(二)

    Requests Requests模块 Requests模块是一个用于网络访问的模块,其实类似的模块有很多,比如urllib,urllib2,httplib,httplib2,他们基本都提供相似的功能 ...

  3. Redis分布式锁实现方式(附有正解及错误示例)

    一.前言 本文内容主要来自博客:https://wudashan.com/2017/10/23/Redis-Distributed-Lock-Implement/,本文用于归纳总结及笔记用途,如有需要 ...

  4. [软件研究]对wdcp v3的一次小研究#1

    0x00 前言 好久没有更新了,已经长草无疑. 之前团队要搞个测验的系统,用来安全培训考核,团队内又没啥人搞开发的,自己又想学一下vue,就用vue+ci 撸了一个. 搞了一个星期基本搞完(开发能力真 ...

  5. C# 设置MDI子窗体只能弹出一个的方法

    Windows程序设计中的MDI(Multiple Document Interface)官方解释就是所谓的多文档界面,与此对应就有单文档界面 (SDI), 它是微软公司从Windows .0下的Mi ...

  6. windows系统,添加网络位置向导。

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha ============ 创建一个文件夹 共享. 共享位置 ,文件夹 图标 修改. 分组 ...

  7. 洛谷 P1114 “非常男女”计划

    To 洛谷.1114 “非常男女”计划 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太多,仅是舞伴),通过各种推理和实验,他掌握了大量的实战经验.例如,据他观察,身高相近的人 ...

  8. stdlib库中qsort函数的使用

    qsort :功 能: 使用快速排序例程进行排序  用 法: void qsort(void *base, int nelem, int width, int (*fcmp)(const void * ...

  9. BZOJ2759一个动态树好题 LCT

    题如其名啊 昨天晚上写了一发忘保存 只好今天又码一遍了 将题目中怕$p[i]$看做$i$的$father$ 可以发现每个联通块都是一个基环树 我们对每个基环删掉环上一条边 就可以得到一个森林了 可以用 ...

  10. EasyUI学习总结(二)——easyloader分析与使用(转载)

    本文转载自:http://www.cnblogs.com/haogj/archive/2013/04/22/3036685.html 使用脚本库总要加载一大堆的样式表和脚本文件,在easyui 中,除 ...