c++定位記憶體洩露
阿新 • • 發佈:2019-01-02
//測試程式碼
#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; } } }