从事C++研发的筒子们,最挥之不去可能要算内存泄露带来的痛苦吧,在C++中,虽说其实现底层代码方面所凸显出来的性能要远高于其他类型语言,但是其由于缺乏天生的内存回收机制,从而也被业界予以诟病,那有没有办法能够监测到程序中的内存泄露问题呢,其实是有很多的办法,例如efence ,vagrind类型的工具等,但是这些工具最大的问题就是太重量级了,需要在自己的代码中安插部分调试代码,使用起来也是不很方便,基于此,本人通过学习前人的一些方法,稍微对new,delete进行了重载,基本上实现了检查程序中的内存泄露问题,好了,下面来看代码吧:
#include<stdio.h> #include<map> #include<boost/thread/mutex.hpp> #include<boost/thread/locks.hpp> using namespace boost; #define MEM_CHECK_TABLESIZE 1024*1024 #define MEM_HASH_FUNC(ptr) ((reinterpret_cast<unsigned long>(ptr))%MEM_CHECK_TABLESIZE) #define MEM_FILENAME_SIZE 1024 boost::mutex mut; boost::mutex mem_mut; struct allocMem_ptr_t { allocMem_ptr_t() { bzero(fileName,sizeof(fileName)); size = 0; line = 0; next = NULL; } char fileName[MEM_FILENAME_SIZE]; int size; int line; allocMem_ptr_t* next; }; struct allocMem_ptr_t* allocMem_list[MEM_CHECK_TABLESIZE]; int tableSize = 0; struct memLeak_ptr_t { memLeak_ptr_t() { bzero(fileName,sizeof(fileName)); size = 0; } char fileName[MEM_FILENAME_SIZE]; int size; }; std::map<int,memLeak_ptr_t> memLeak_map; void memCheck() { size_t index = 0; mem_mut.lock(); for(int i=0;i<MEM_CHECK_TABLESIZE;i++) { allocMem_ptr_t* alloc = allocMem_list[i]; if(NULL == alloc) continue; while(alloc) { memLeak_ptr_t memLeak; sprintf(memLeak.fileName,"%s:%d",alloc->fileName,alloc->line); memLeak.size = alloc->size; memLeak_map.insert(std::make_pair(index,memLeak)); alloc = alloc->next; index++; } } mem_mut.unlock(); std::map<std::string,int> leakCount; for(int i =0;i<memLeak_map.size();i++) leakCount[memLeak_map[i].fileName] += memLeak_map[i].size; typedef std::map<std::string,int>::iterator leakCount_iter; for(leakCount_iter iter = leakCount.begin();iter != leakCount.end();++iter) { printf("%s LEAK MEMORY SIZE:%d\n",iter->first.c_str(),iter->second); } } void* operator new(size_t size,const char* file,int line) { size_t siz = size + sizeof(allocMem_ptr_t); allocMem_ptr_t* ptr = (allocMem_ptr_t*)::malloc(siz); if(NULL == ptr) abort(); void* p = (char*)ptr + sizeof(allocMem_ptr_t); strncpy(ptr->fileName,file,MEM_FILENAME_SIZE-1); ptr->size = size; ptr->line = line; mem_mut.lock(); size_t index = MEM_HASH_FUNC(p); ptr->next = allocMem_list[index]; allocMem_list[index] = ptr; ++tableSize; mem_mut.unlock(); return p; } void* operator new[](size_t size,const char* file,int line) { return operator new(size,file,line); } void operator delete(void* ptr) { if(NULL == ptr) return; allocMem_ptr_t* pre = NULL; size_t index = MEM_HASH_FUNC(ptr); mem_mut.lock(); allocMem_ptr_t* pointer = allocMem_list[index]; while(pointer) { if((char*)pointer + sizeof(allocMem_ptr_t) == ptr) { if(NULL == pre) allocMem_list[index] = pointer->next; else pre->next = pointer->next; --tableSize; break; } pre = pointer; pointer = pointer->next; } mem_mut.unlock(); free(pointer); } void operator delete[](void* pointer) { operator delete(pointer); } void operator delete(void* pointer,const char* file,int line) { operator delete(pointer); } void operator delete[](void* pointer,const char* file,int line) { operator delete(pointer); }
#ifndef __MEM_CHECK__H #define __MEM_CHECK__H #include<stdio.h> #include<string> #define MEM_CHECK memCheck() void memCheck(); void* operator new(size_t size,const char* file,int line); void* operator new[](size_t size,const char* file,int line); void operator delete(void* pointer,const char* file,int line); void operator delete[](void* pointer,const char* file,int line); #define MEM_ALLOC new(__FILE__,__LINE__) #define MEM_DELETE delete #endif
测试程序:
#include "MemCheck.h" struct point { point() { posX = 0; posY = 0; } int posX; int posY; }; int main(int argc,char* argv[]) { int* pointer = MEM_ALLOC int(); double* doub = MEM_ALLOC double(); std::string* str = MEM_ALLOC std::string(); point* po = MEM_ALLOC point(); MEM_DELETE pointer; MEM_DELETE po; MEM_CHECK; return 0; }
测试结果:
Test.cpp:18 LEAK MEMORY SIZE:8 Test.cpp:19 LEAK MEMORY SIZE:4
总结
本篇博文主要是通过封装new、delete操作,实现了一个简单版的检查内存泄露工具,原理很简单:通过一个简单的hash表来存放相关的内存分配信息,这个hash表会随着内存分配操作而动态的调整,这个实现思路其实还是有部分的问题,但总体上来将还是应用于实际的项目,好好地体会吧,有机会的话,我们可以使用redis来改写下这个功能,好了,本篇博文到此结束。
如果需要,请注明转载,多谢