16,473
社区成员
发帖
与我相关
我的任务
分享
/************************************************************************
* 类名:CMemPool
* 功能:windows内存池。
1、此内存池的目的主要是方便定位内存泄露
2、调试开关打开的时候会将内存泄露的信息打印出来
3、注意:此内存池只分配内存,不会调用构造函数,不适用于自定义
数据类型(只针对char、int、short、double等基本数据类型)
* 作者:王威
* 时间:2013-03-12
* 版本:1.0.0.1
************************************************************************/
#pragma once
#include <fstream>
#include <list>
using namespace std;
template<typename T>
class CMemPool
{
private:
struct SM
{
int size; //申请的内存大小
T* pt; //申请的内存首地址
unsigned char flg; //0从未使用的内存, 1正在使用, 2回收的内存
};
CMemPool(const CMemPool&){}; //禁止拷贝构造
list<SM> m_list;
CRITICAL_SECTION m_csMemLock;
#ifdef _DEBUG
CString m_csLogPath;
#endif
CMemPool(int size = 1)
{
InitializeCriticalSection(&m_csMemLock);
SM sm;
for(int i = 0; i < size; ++i)
{
sm.size = 512;
sm.pt = (T*)malloc(sizeof(T)*512);
sm.flg = 0;
m_list.push_front(sm);
}
#ifdef _DEBUG
//获取日志文件目录
char szPath[MAX_PATH] = {0};
::GetModuleFileNameA(NULL, szPath, MAX_PATH);
m_csLogPath = szPath;
int pos = m_csLogPath.ReverseFind(_T('\\'));
m_csLogPath = m_csLogPath.Left(pos+1);
m_csLogPath += "MemPool.log";
std::locale::global(std::locale(""));//使用STL函数设置为系统语言环境,解决bug:fstream不支持中文目录路径
ofstream out2file(m_csLogPath, ios::out);
out2file.close();
#endif
};
public:
static CMemPool<T>* Instance(int size = 20)
{
static CMemPool<T> ins(size);
return &ins;
};
virtual ~CMemPool()
{
CheckMemeryLeak();
DeleteCriticalSection(&m_csMemLock);
list<SM>::iterator it;
for(it = m_list.begin(); it != m_list.end(); ++it)
{
free(it->pt);
}
m_list.clear();
};
T* New(int size = 1, const char* file = "", const char* func = "", int line = 0)
{
EnterCriticalSection(&m_csMemLock);
#ifdef _DEBUG
string filestr(file);
string::size_type fid = filestr.rfind('\\');
if (fid != string::npos)
{
filestr = filestr.substr(fid+1, filestr.length()-fid-1);
}
ofstream out2file(m_csLogPath, ios::app);
#endif
if (m_list.size() < 1 || m_list.front().flg == 1) //池为空或者没有空闲的内存需要重新申请
{
#ifdef _DEBUG
if (out2file.is_open())
{
out2file<<filestr<<"("<<line<<") : "<<func<<"----New:池为空或者没有空闲的内存需要重新申请, size="<<size<<", m_list.size() = "<<m_list.size()+1<<"\n";
}
#endif
SM sm;
sm.size = size;
sm.pt = (T*)malloc(sizeof(T)*size);
sm.flg = 0;
m_list.push_front(sm);
}
SM tsm = m_list.front();
if (tsm.size < size) //改变大小
{
tsm.pt = (T*)realloc(tsm.pt, sizeof(T)*size);
#ifdef _DEBUG
if (out2file.is_open())
{
CString addr;
addr.Format("0x%p", tsm.pt);
out2file<<filestr<<"("<<line<<") : "<<func<<"----New:改变大小 首地址="<<addr<<", from "<<tsm.size<<" to "<<size<<"\n";
}
out2file.close();
#endif
tsm.size = size;
}
else
{
#ifdef _DEBUG
if (out2file.is_open())
{
CString addr;
addr.Format("0x%p", tsm.pt);
out2file<<filestr<<"("<<line<<") : "<<func<<"----New:从池中取出内存, 首地址="<<addr<<" , size= "<<tsm.size<<"\n";
}
out2file.close();
#endif
}
tsm.flg = 1; //设置此节点内存不可分配
m_list.pop_front(); //从头部删除
m_list.push_back(tsm); //插入到尾部
LeaveCriticalSection(&m_csMemLock);
return tsm.pt;
};
void Delete(void* pt, const char* file, const char* func, int line)
{
EnterCriticalSection(&m_csMemLock);
#ifdef _DEBUG
string filestr(file);
string::size_type fid = filestr.rfind('\\');
if (fid != string::npos)
{
filestr = filestr.substr(fid+1, filestr.length()-fid-1);
}
ofstream out2file(m_csLogPath, ios::app);
#endif
if (pt == 0)
{
#ifdef _DEBUG
if (out2file.is_open())
{
out2file<<filestr<<"("<<line<<") : "<<func<<"----Delete:传入了空指针"<<"\n";
}
out2file.close();
#endif
LeaveCriticalSection(&m_csMemLock);
return;
}
list<SM>::reverse_iterator rit;
for (rit = m_list.rbegin(); rit != m_list.rend(); ++rit)
{
if (rit->pt == (T*)pt)//找到了要释放的内存
{
if(rit->flg == 0)
{
#ifdef _DEBUG
if (out2file.is_open())
{
CString addr;
addr.Format("0x%p", pt);
out2file<<filestr<<"("<<line<<") : "<<func<<"----Delete:找到了要释放的内存,但是改内存不是从池中New出来的, 首地址="<<addr<<"\n";
}
out2file.close();
#endif
LeaveCriticalSection(&m_csMemLock);
return;
}
else if(rit->flg == 2)
{
#ifdef _DEBUG
if (out2file.is_open())
{
CString addr;
addr.Format("0x%p", pt);
out2file<<filestr<<"("<<line<<") : "<<func<<"----Delete:找到了要释放的内存,但是该内存是池中已经释放的, 首地址="<<addr<<"\n";
}
out2file.close();
#endif
LeaveCriticalSection(&m_csMemLock);
return;
}
SM tsm;
tsm.flg = 2;
tsm.pt = rit->pt;
tsm.size = rit->size;
m_list.erase(--rit.base());
m_list.push_front(tsm);
#ifdef _DEBUG
if (out2file.is_open())
{
CString addr;
addr.Format("0x%p", pt);
out2file<<filestr<<"("<<line<<") : "<<func<<"----Delete:成功释放内存, 首地址="<<addr<<"\n";
}
out2file.close();
#endif
LeaveCriticalSection(&m_csMemLock);
return;
}
}
#ifdef _DEBUG
if (out2file.is_open())
{
out2file<<filestr<<"("<<line<<") : "<<func<<"----Delete:没有找到要释放的内存"<<"\n";
}
out2file.close();
#endif
LeaveCriticalSection(&m_csMemLock);
};
void CheckMemeryLeak()
{
#ifdef _DEBUG
EnterCriticalSection(&m_csMemLock);
ofstream out2file(m_csLogPath, ios::app);
list<SM>::iterator it;
out2file<<"开始统计泄露的内存:"<<"\n";
for (it = m_list.begin(); it != m_list.end(); ++it)
{
if (it->flg == 1)//正在使用的内存才是泄露
{
if (out2file.is_open())
{
CString addr;
addr.Format("0x%p", it->pt);
out2file<<"CheckMemLeak:检测到内存泄露, 地址是:"<<addr<<", size:"<<it->size<<"\n";
}
}
}
out2file.close();
LeaveCriticalSection(&m_csMemLock);
#endif
};
};
//初始化池
#define pool_init(size) (CMemPool<char>::Instance(size))
//安全的new
#define s_new(size) (CMemPool<char>::Instance()->New(size, __FILE__, __FUNCTION__, __LINE__))
//安全的delete
#define s_delete(p) (CMemPool<char>::Instance()->Delete(p, __FILE__, __FUNCTION__, __LINE__))