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秒输出一次内存分配情况#endifstruct 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);#elseEnterCriticalSection(&m_mtx);#endif}void unlock(){ #ifdef __linux__pthread_mutex_unlock(&m_mtx);#elseLeaveCriticalSection(&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;#elseCRITICAL_SECTION m_mtx;#endif};//#ifdef DEBUG_REPORT_NEW_ALLOCinline 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_VERCDumpMemoryLeaks::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);#elseInitializeCriticalSection(&m_mtx);#endif}CDumpMemoryLeaks::~CDumpMemoryLeaks(void){ if (m_fpDumpFile){ fclose(m_fpDumpFile);m_fpDumpFile = NULL;}#ifdef __linux__pthread_mutex_destroy(&m_mtx);#elseDeleteCriticalSection(&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