1. 程式人生 > >c++定位記憶體洩露

c++定位記憶體洩露

//測試程式碼
#include "DebugTracer.h"

//主要的思路是:
// 1.過載new,在過載的new中儲存new出來的地址,new的檔名(__FILE___),new的行數(__LINE__)
//2.將該new的資訊存放在一個容器中,delete時,刪除一個,程式結束,還在容器中的指標,就是已經洩露的指標
int main()
{
	int*p = new int;
	delete p;
	int *p1 = new int[10];
    return 0;
}

用來控制debug下有效,release無效

#ifndef __DUBUG_TRACER_H_
#define __DUBUG_TRACER_H_
#ifndef NDEBUG
#include "Tracer.h"

#define new new(__FILE__,__LINE__)
#endif //!NDEBUG
#endif //!__DUBUG_TRACER_H_

 

1.過載new/delete,容器存放new資訊,並在析構時列印

 

#ifndef __TRACER_H_
#define __TRACER_H_
#include <stdlib.h>
#include <map>
//操作符過載,全域性過載
//該函式是自己new的時候,呼叫的,new[]底層呼叫的new
void* operator new(size_t size, const char* filename, const long line);
//該函式是第三方,new的時候,呼叫的。比如dll,庫
void* operator new(size_t size);
//delete[] 他是一個單獨的函式
void operator delete(void* pointer);
void operator delete[](void* pointer);
class Tracer
{
public:
	Tracer();
	~Tracer();
	class  Entry 
	{
	public:
		Entry(const char* file = nullptr, const long line = 0)
			:m_file(file), m_line(line) {}
		inline const char* File()
		{
			return m_file;
		}
		inline const long Line()
		{
			return m_line;
		}
	private:
		const char* m_file;
		const long m_line;
	};
	class Lock
	{
	public:
		Lock(Tracer& tracer)
			:m_Tracer(tracer)
		{
			m_Tracer.m_count++;
		}
		~Lock()
		{
			m_Tracer.m_count--;
		}
	private:
		Tracer &m_Tracer;
	};
	void Add(void* pointer, const char* file, const long line);
	void Remove(void* pointer);
	void Dump();
	static bool m_Ready; //是防止物件沒生成,呼叫delete,從而導致程式過載,導致崩潰
private:
	std::map<void*, Entry> m_Tracer_Info_Map;
	long m_count; //是防止第三方呼叫了形成遞迴,比如new進了void* operator new(size_t size);就會在進Add,然後會再進map中的new,從而無限迴圈
};

#endif //!__TRACER_H_

實現檔案

#include "Tracer.h"
#include "iostream"

Tracer tracer;
//static 全域性定義時,需要使用型別名
bool Tracer::m_Ready = false;
void* operator new(size_t size, const char* filename, const long line)
{
	void* p = malloc(size);
	if (Tracer::m_Ready)
	{
		tracer.Add(p, filename, line);
		return p;
	}
	return p;
}
//該函式是別人new的時候,呼叫的
void* operator new(size_t size)
{
	void* p = malloc(size);
	if (Tracer::m_Ready)
	{
		tracer.Add(p, "Unknow", -1);
		return p;
	}
	return p;
}
void operator delete(void* pointer)
{
	if (Tracer::m_Ready)
	{
		tracer.Remove(pointer);
	}
	free(pointer);
}
void operator delete[](void* pointer)
{
	if (Tracer::m_Ready)
	{
		tracer.Remove(pointer);
	}
	free(pointer);
}
Tracer::Tracer()
{
	Tracer::m_Ready = true;
	m_count = 0;
}


Tracer::~Tracer()
{
	Dump();
	Tracer::m_Ready = false;
}
void Tracer::Add(void* pointer, const char* file, const long line)
{
	if (m_count > 0)
	{
		return;
	}
	Lock(*this);
	Entry temp(file, line);
	m_Tracer_Info_Map.emplace(std::make_pair(pointer, std::move(temp)));
	
}
void Tracer::Remove(void* pointer)
{
	if (m_count > 0)
	{
		return;
	}
	Lock(*this);
	auto iter = m_Tracer_Info_Map.find(pointer);
	if (iter != m_Tracer_Info_Map.end())
	{
		m_Tracer_Info_Map.erase(iter);
	}
}
void Tracer::Dump()
{
	if (!m_Tracer_Info_Map.empty())
	{
		std::cout << "記憶體洩露" << std::endl;
		for (auto& i : m_Tracer_Info_Map)
		{
			std::cout << i.second.File() << ":" << i.second.Line() << std::endl;
		}
	}
}