C++内存泄露的检测(三)
一 简单的对内存的分配和释放跟踪,并将结果输出到console,它也是一般C++内存泄露的检测原理,来自C++编程思想:
(比较简单,大家都可以看的明白的哦)实现如下:
MemCheck.h
//: C02:MemCheck.h #ifndef MEMCHECK_H #define MEMCHECK_H #include <cstddef> // for size_t // Hijack the new operator (both scalar and array versions) void* operator new(std::size_t, const char*, long); void* operator new[](std::size_t, const char*, long); #define new new (__FILE__, __LINE__) extern bool traceFlag; #define TRACE_ON() traceFlag = true #define TRACE_OFF() traceFlag = false extern bool activeFlag; #define MEM_ON() activeFlag = true #define MEM_OFF() activeFlag = false #endif
MemCheck.cpp
//: C02:MemCheck.cpp {O} #include <cstdio> #include <cstdlib> #include <cassert> using namespace std; #undef new // Global flags set by macros in MemCheck.h bool traceFlag = true; bool activeFlag = false; namespace { // Memory map entry type struct Info { void* ptr; const char* file; long line; }; // Memory map data const size_t MAXPTRS = 10000u; Info memMap[MAXPTRS]; size_t nptrs = 0; // Searches the map for an address int findPtr(void* p) { for (int i = 0; i < nptrs; ++i) if (memMap[i].ptr == p) return i; return -1; } void delPtr(void* p) { int pos = findPtr(p); assert(p >= 0); // Remove pointer from map for (size_t i = pos; i < nptrs-1; ++i) memMap[i] = memMap[i+1]; --nptrs; } // Dummy type for static destructor struct Sentinel { ~Sentinel() { if (nptrs > 0) { printf("Leaked memory at:\n"); for (size_t i = 0; i < nptrs; ++i) printf("\t%p (file: %s, line %ld)\n", memMap[i].ptr, memMap[i].file, memMap[i].line); } else printf("No user memory leaks!\n"); } }; // Static dummy object Sentinel s; } // End anonymous namespace // Overload scalar new void* operator new(size_t siz, const char* file, long line) { void* p = malloc(siz); if (activeFlag) { if (nptrs == MAXPTRS) { printf("memory map too small (increase MAXPTRS)\n"); exit(1); } memMap[nptrs].ptr = p; memMap[nptrs].file = file; memMap[nptrs].line = line; ++nptrs; } if (traceFlag) { printf("Allocated %u bytes at address %p ", siz, p); printf("(file: %s, line: %ld)\n", file, line); } return p; } // Overload array new void* operator new[](size_t siz, const char* file, long line) { return operator new(siz, file, line); } // Override scalar delete void operator delete(void* p) { if (findPtr(p) >= 0) { free(p); assert(nptrs > 0); delPtr(p); if (traceFlag) printf("Deleted memory at address %p\n", p); } else if (!p && activeFlag) printf("Attempt to delete unknown pointer: %p\n", p); } // Override array delete void operator delete[](void* p) { operator delete(p); } /**////:~
二 说明:
1)通过重载new和delete来实现
2)使用时需要在工程中加入MemCheck.h和MemCheck.cpp,在需要检测的文件的前面include “MemCheck.h”,但是必须在所有的include的最后。
3)MEM_ON(),MEM_OFF()用来打开或关闭检测
4)TRACE_ON(),和TRACE_OFF()用来打开或关闭检测结果的输出
5)可以检测代码中使用了流,标准容器,以及某个类的构造函数分配了空间
三 使用实例:
console 的project中加入下面的file:
// MemoryLeak3.cpp : Defines the entry point for the console application. // #include <iostream> #include <vector> #include <cstring> #include "MemCheck.h" // Must appear last! using namespace std; void Test() { int *i = new int(0); } class MyClass { private: int *p; public: MyClass() { if(p != NULL) { p = new int(0); } } ~MyClass() { if(p != NULL) { delete p; p = NULL; } } }; void Test2() { int *i = NULL; // better for read i = new int(0); int *&y = i; // pointer's reference delete i; MyClass *pMyClass = new MyClass(); std::vector<MyClass*> myClasses; myClasses.push_back(new MyClass()); myClasses.push_back(new MyClass()); std::vector<void*> myVector; myVector.push_back(new MyClass()); myVector.push_back(new MyClass()); delete (MyClass *)(myVector.at(0)); delete myVector.at(1); // memory leak } class Foo { char* s; public: Foo(const char*s ) { this->s = new char[strlen(s) + 1]; strcpy(this->s, s); } ~Foo() { delete [] s; } }; void Test3() { cout << "hello\n"; int* p = new int; delete p; int* q = new int[3]; delete [] q; int* r; /**//*delete r;*/ vector<int> v; v.push_back(1); Foo s("goodbye"); } int main() { TRACE_OFF(); MEM_ON(); Test(); Test2(); Test3(); MEM_OFF(); } /**////:~
四 测试结果如下