C++内存泄漏检测(调试工具)

理论

  • 什么是内存泄露:指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

工具作用

  • 在使用Debug版的malloc分配内存时,malloc会在内存块的头中记录分配该内存的文件名及行号。
  • 当程序退出时会在main()函数返回之后做一些清理工作,这个时候来检查调试堆内存,如果仍然有内存没有被释放,则一定是存在内存泄漏。
  • 从没有被释放的内存块,就可以获得文件名、行号,泄漏多少字节,会打印显示出来。
  • 如下图所示,内存泄漏检测工具运行的效果。

C++内存泄漏检测(调试工具)

Debug调试常用的宏

__FILE__            //所在的文件
__FUNCTION__        //函数功能
__FUNCDNAME__       //函数名
__LINE__            //在第几行
__DATE__            //产生的日期
__TIME__            //产生的时间

代码实现

MemoryCheck.h

#pragma once
#ifndef __MEMORY_CHECK_H__
#define __MEMORY_CHECK_H__
#ifdef _DEBUG

void* operator new(size_t size, const char* filename, const char* funame, int line);
void* operator new[](size_t size, const char* filename, const char* funame, int line);
void operator delete(void* pMem);
void operator delete[](void* pMem);

#ifndef __USE_MEM_CHECK__
#define __USE_MEM_CHECK__
#define new new(__FILE__,__FUNCTION__,__LINE__)
#endif // !__USE_MEM_CHECK__
#endif // _DEBUG
#endif // !__MEMORY_CHECK_H__

MemoryCheck.cpp

#include<map>
#include<iostream>
#include<Windows.h>
#define __USE_MEM_CHECK__
#include"MemoryCheck.h"

typedef struct stMemInfo
{
    void* pMem;
    size_t size;
    int line;
    char funcname[256];
    char filename[256];
}MEMINFO,*LPMEMINFO;


std::map<void*, LPMEMINFO>g_MemMap;//存储内存分配的信息
typedef std::map<void*, LPMEMINFO>MEMMAP;
typedef MEMMAP::iterator MEMMAPItr;

class CMemMgr
{
public:
    static CMemMgr& Instance()
    {
        static CMemMgr instance;
        return instance;
    }

    void* Push(LPMEMINFO pInfo)
    {
        g_MemMap[pInfo->pMem] = pInfo;
        return pInfo->pMem;
    }
    void Pop(void* pMem)
    {
        MEMMAPItr it = g_MemMap.find(pMem);
        if (it != g_MemMap.end())
        {
            free(pMem);
            free(it->second);
            g_MemMap.erase(it);
        }
    }
    ~CMemMgr()
    {
        if (!g_MemMap.empty())
        {
            OutputDebugStringA("n----------------------------------发现内存泄露信息----------------------------------nn");
            char buf[256] = {};
            int count = 0;
            for (auto it:g_MemMap)
            {
                sprintf_s(buf, "【内存泄漏警告 %d 】 文件%s,第%d行的函数%s中泄漏了%d个字节的内存n",
                    count++,
                    it.second->filename,
                    it.second->line,
                    it.second->funcname,
                    it.second->size);

                OutputDebugStringA(buf);
                free(it.second->pMem);
                free(it.second);
            }
            g_MemMap.clear();
            OutputDebugStringA("n-------------------------------内存泄漏检测结束----------------------------------nn");
        }
    }
private:
    CMemMgr() {};
    CMemMgr& operator=(const CMemMgr&) = delete;
    CMemMgr(const CMemMgr&) = delete;
};


void* operator new(size_t size, const char* filename, const char* funcname, int line)
{
    LPMEMINFO pInfo=(LPMEMINFO)malloc(sizeof(MEMINFO));
    pInfo->size = size;
    pInfo->line = line;
    pInfo->pMem = malloc(size);
    strcpy_s(pInfo->filename, filename);
    strcpy_s(pInfo->funcname, funcname);
    return CMemMgr::Instance().Push(pInfo);
}
void* operator new[](size_t size, const char* filename, const char* funcname, int line)
{
    return operator new(size, filename, funcname, line);
}
void operator delete(void* pMem)
{
    CMemMgr::Instance().Pop(pMem);
}
void operator delete[](void* pMem)
{
    operator delete(pMem);
}

main.cpp

#include<iostream>
#include"MemoryCheck.h"

int main()
{
    int* p = new int;
    int* p2 = new int[5];
    system("pause");
    return 0;
}

注意

  • 重载的new相冲突解决办法:
  • 1.使用宏定义开关#define USE_MEM_CHECK,定义在MemoryCheckr.h的前面才能实现宏定义开关,注意顺序很重要,顺序错误也会导致不识别。
  • 2.使用#undef new也可解决

原文链接: https://www.cnblogs.com/biu-we/p/13360000.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C++内存泄漏检测(调试工具)

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/369587

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午7:01
下一篇 2023年3月2日 下午7:01

相关推荐