zoukankan      html  css  js  c++  java
  • C++内存泄漏检测(调试工具)

    理论

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

    工具作用

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

    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("
    ----------------------------------发现内存泄露信息----------------------------------
    
    ");
    			char buf[256] = {};
    			int count = 0;
    			for (auto it:g_MemMap)
    			{
    				sprintf_s(buf, "【内存泄漏警告 %d 】 文件%s,第%d行的函数%s中泄漏了%d个字节的内存
    ",
    					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("
    -------------------------------内存泄漏检测结束----------------------------------
    
    ");
    		}
    	}
    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也可解决
  • 相关阅读:
    Object-C 类
    POJ 2128:Highways
    默认连接电脑的模式为MTP【转】
    java.lang.ClassFormatError Duplicate field name&signature in class file XXXXXX【转】
    吴恩达机器学习--单变量线性回归【学习笔记】
    用代码实现断开Android手机USB连接【转】
    Android系统属性SystemProperties在应用层的用法【转】
    [RK3288][Android6.0] 调试笔记 --- user版本默认显示开发者选项【转】
    如何彻底禁止手机连接usb,代码实…【转】
    Android关闭USB的ADB调试和文件传输功能(禁用USB)【转】
  • 原文地址:https://www.cnblogs.com/biu-we/p/13360000.html
Copyright © 2011-2022 走看看