C++内存泄漏检测代码

我们在进行C++编码的时候,难免会遇到内存泄漏的时候,特别是一些新手朋友们在编码完成后花大量的时间解决BUG,在该文章我用代码剖析跟踪内存泄漏的原理,熟悉C/C++的朋友都知道内存分配和释放都是要成对调用的,如果某处代码只分配内存,而没有释放就会造成内存泄漏的bug。

 

下面帖出我写的内存泄漏跟踪类的代码:

MemLeakTrack.h文件

#pragma once
#ifndef INC_TRACK_ALLOC_H
#define INC_TRACK_ALLOC_H
//
// 内存泄漏检测工具
//
// 使用方法:
// 将此对象的头和源文件添加到工程,并在stdafx.h中包含头文件即可
//

#include <unordered_map>

void* operator new (size_t size, LPCSTR pszFileName, int nLine);
void operator delete (void* ptr);

#ifdef DEBUG_NEW
#undef DEBUG_NEW
#endif

#define DEBUG_NEW new (__FILE__, __LINE__)


//

class MemLeakTrack
{
	class AllocItem
	{
	public:
		AllocItem() = default;
		AllocItem(void *ptr, size_t size, LPCSTR pszFileName, int nLine)
			: m_ptr(ptr)
			, m_size(size)
			, m_pszFileName(pszFileName)
			, m_nLine(nLine)
		{}

		AllocItem(const AllocItem &src)
		{
			*this = std::move(src);
		}

		AllocItem& operator=(const AllocItem& src)
		{
			*this = std::move(src);
			return *this;
		}

	public:
		inline const void* Ptr() const { return m_ptr; }
		inline size_t Size() const { return m_size; }
		inline LPCSTR FileName() const { return m_pszFileName; }
		inline int Line() const { return m_nLine; }

	protected:
		size_t		m_size = 0;						//分配尺寸
		int			m_nLine = 0;					//代码行数
		void*		m_ptr = nullptr;				//内存地址
		LPCSTR		m_pszFileName = nullptr;		//代码文件
	};

	class AllocCounter
	{
	public:
		AllocCounter() = default;
		AllocCounter(LPCSTR pszFileName, int nLine)
			: m_pszFileName(pszFileName)
			, m_nLine(nLine)
			, m_nCounter(0)
		{}

		AllocCounter(const AllocCounter &src)
		{
			*this = std::move(src);
		}

		AllocCounter& operator=(const AllocCounter& src)
		{
			*this = std::move(src);
			return *this;
		}

		inline LPCSTR FileName() const { return m_pszFileName; }
		inline int Line() const { return m_nLine; }
		inline ULONG Counter() const { return m_nCounter; }
		inline void Add() { m_nCounter++; }

	protected:
		LPCSTR			m_pszFileName = nullptr;
		int				m_nLine = 0;
		ULONG			m_nCounter = 0;
	};
public:
	MemLeakTrack();
	~MemLeakTrack();

	void Add(void *ptr, size_t size, LPCSTR pszFileName, int nLine);
	void Remove(void *ptr);
	void Dumps();
	static bool IsActive() { return m_bActive; }

protected:
	DWORD GetHashCode(LPCSTR pszFileName, int nLine);

protected:
	static bool m_bActive;		//保证此对象生命周期内可用
	std::tr1::unordered_map<void*, AllocItem>		m_AllocItems;
	std::tr1::unordered_map<DWORD, AllocCounter>	m_AllocCounter;
};


#endif //INC_TRACK_ALLOC_H

MemLeakTrack.cpp文件

#include "stdafx.h"
#include "MemLeakTrack.h"

MemLeakTrack theMemLeakTrack;

void* operator new (size_t size, LPCSTR pszFileName, int nLine)
{
	void *ptr = malloc(size);
	if (MemLeakTrack::IsActive())
		theMemLeakTrack.Add(ptr, size, pszFileName, nLine);

	return ptr;
}

void operator delete (void* ptr)
{
	if (MemLeakTrack::IsActive())
		theMemLeakTrack.Remove(ptr);

	free(ptr);
}

//

bool MemLeakTrack::m_bActive = false;

MemLeakTrack::MemLeakTrack()
{
	MemLeakTrack::m_bActive = true;
}


MemLeakTrack::~MemLeakTrack()
{
	MemLeakTrack::m_bActive = false;
	Dumps();
}

void MemLeakTrack::Add(void *ptr, size_t size, LPCSTR pszFileName, int nLine)
{
	//使用原生new防止递归调用
#pragma push_macro("new")
#undef new
	m_AllocItems[ptr] = AllocItem(ptr, size, pszFileName, nLine);
	DWORD dwHash = GetHashCode(pszFileName, nLine);

	//分配计数
	auto iter = m_AllocCounter.find(dwHash);
	if (iter == m_AllocCounter.end())
		m_AllocCounter[dwHash] = AllocCounter(pszFileName, nLine);

	m_AllocCounter[dwHash].Add();

#pragma pop_macro("new")
}

void MemLeakTrack::Remove(void *ptr)
{
#pragma push_macro("delete")
#undef delete
	auto it = m_AllocItems.find(ptr);
	if (it != m_AllocItems.end())
	{
		m_AllocItems.erase(it);
	}
#pragma pop_macro("delete")

}

void MemLeakTrack::Dumps()
{
	TCHAR szBuffer[512] = { 0 };

	std::vector<AllocCounter> rankList;
	rankList.reserve(m_AllocCounter.size());

	for (auto it = m_AllocCounter.begin(); it != m_AllocCounter.end(); ++it)
	{
		rankList.push_back(it->second);
	}

	//对排名进行排序
	std::sort(rankList.begin(), rankList.end(), [](const AllocCounter &a, const AllocCounter &b) {
		return a.Counter() > b.Counter();
	});

	//打印计数排名
	OutputDebugString(TEXT("Memory allocation count ranking:\n"));
	for (auto &item : rankList)
	{
		_stprintf_s(szBuffer, _countof(szBuffer), TEXT("Alloc counter:%u \t\tFile(%d) %hs\n"), item.Counter(), item.Line(), item.FileName());
		OutputDebugString(szBuffer);
	}

	//打印未释放的内存
	for (auto it = m_AllocItems.begin(); it != m_AllocItems.end(); ++it)
	{
		_stprintf_s(szBuffer, _countof(szBuffer), TEXT("normal block at 0x%p, %d byte long.\nFile(%d):%hs\n"),
			it->first,
			it->second.Size(),
			it->second.Line(),
			it->second.FileName());

		OutputDebugString(szBuffer);
	}
}

DWORD MemLeakTrack::GetHashCode(LPCSTR pszFileName, int nLine)
{
	CHAR szBuffer[512] = { 0 };
	sprintf_s(szBuffer, _countof(szBuffer), "File(%d) %s", nLine, pszFileName);
	return std::hash<std::string>{}(szBuffer);
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值