zoukankan      html  css  js  c++  java
  • C++:重载全局new/delete实现跨平台多线程内存检测

    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 ",(unsigned long)nTotalAlloc);



    m_strMsg += " ";



    m_strMsg += m_szBuf;



    m_strMsg += "-------------------------------------------------------------------------- ";



    snprintf(m_szBuf,sizeof(m_szBuf)-1,

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

    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 ",

    itorLocalList->m_strFile.c_str(),

    itorLocalList->m_nLine,

    nSize,

    nSize*dTotalReciprocal*100,

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

    );



    m_strMsg += m_szBuf;

    }



    m_strMsg += "-------------------------------------------------------------------------- ";



    }



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

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



    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, " ---------------- DumpMemoryLeaks begin! ---------------- ");



    }

    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 ", this);

    }



    ~B()

    {

    printf("delete B instance %p ", 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 

  • 相关阅读:
    训练深度学习网络时候,出现Nan 或者 震荡
    Jupyter Notebook 的快捷键
    pyspark RandomForestRegressor 随机森林回归
    深度学习图像标注工具VGG Image Annotator (VIA)使用教程
    python 中 with 用法
    python 报错 SyntaxError: Non-ASCII character
    YOLO 详解
    Spark与Pandas中DataFrame对比
    利用WGET下载文件,并保存到指定目录
    http 三次握手
  • 原文地址:https://www.cnblogs.com/skying555/p/9749175.html
Copyright © 2011-2022 走看看