理論
- 什么是內存泄露:指因為疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況。內存泄漏並不是指內存在物理上的消失,而是應用程序分配某段內存后,因為設計錯誤,失去了對該段內存的控制,因而造成了內存的浪費。
工具作用
- 在使用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("\n----------------------------------發現內存泄露信息----------------------------------\n\n");
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-------------------------------內存泄漏檢測結束----------------------------------\n\n");
}
}
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也可解決