从事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来改写下这个功能,好了,本篇博文到此结束。
如果需要,请注明转载,多谢