MemoryPool
内存池这东西确实很有用。简单的说可以提高性能、减少碎片、帮助查错。MemoryPool的实现也有很多版本,SGI-STL里的实现就很不错。我自己也瞎折腾了一个Demo。
另外可以参考下相关的文章:
C++ Memory Pool http://www.codeproject.com/KB/cpp/MemoryPool.aspx
C++ Memory Pool 汉译版 http://blog.csdn.net/060/archive/2006/10/08/1326025.aspx
Object Pooling for Generic C++ classes http://www.codeproject.com/KB/cpp/objpool.aspx
Object Pooling using C# http://www.codeproject.com/KB/cs/ObjectPooling.aspx
記憶體配置:Pooled Allocation技術評比與效能測試 http://blog.monkeypotion.net/gameprog/advanced/profiling-in-pooled-allocation-techniques#
#include <vector>
#include <map>
#include <set>
#include <cassert>
#include <algorithm>
/// @brief 禁用Win下的min、max宏。为啥要禁?请参阅《MACRO max & MACRO min》
#undef max
#undef min
class CMathUtility
{
public:
/// @brief 将size向上取整到boundModule的倍数
static size_t UpBoundTo(size_t size, size_t boundModule)
{
assert(boundModule > 0);
if(size % boundModule != 0)
size = (size / boundModule + 1) * boundModule;
assert(size % boundModule == 0);
return size;
}
};
/// @brief 定长内存池实现
class CFixSizeMemoryPool
{
typedef unsigned char byte_t;
public:
CFixSizeMemoryPool(size_t nodeSize, size_t iniNodeCount, size_t nodeCountInBlock)
: m_BlockCount(std::max(1U, nodeCountInBlock))
, m_pFreeHead(NULL)
{
assert(nodeSize > 0);
// 保证每个Block至少包含一个Node
m_NodeSize = std::max(sizeof(byte_t*), nodeSize);
// 分配初始内存
if(iniNodeCount != 0)
{
const size_t c = iniNodeCount / m_BlockCount + (iniNodeCount % m_BlockCount != 0);
for(size_t i = 0; i < c; i++)
AddNewBlock();
}
}
~CFixSizeMemoryPool()
{
for(std::vector<byte_t*>::const_iterator it = m_BlockAddr.begin(); it != m_BlockAddr.end(); ++it)
delete[] (byte_t*)(*it);
m_BlockAddr.clear();
}
public:
/// @brief 原生的内存分配。如果用于对象,请注意调用构造函数
void* RawAlloc()
{
if(m_pFreeHead == NULL)
AddNewBlock();
byte_t* ret = m_pFreeHead;
m_pFreeHead = *(byte_t**)m_pFreeHead;
return ret;
}
template<typename T>
T* Alloc()
{
assert(sizeof(T) <= m_NodeSize);
return ::new(RawAlloc()) T();
}
template<typename T>
void Free(T*& p)
{
byte_t* bp = (byte_t*)p;
#ifdef _DEBUG
assert(p);
bool checkflag = false;
for(std::vector<byte_t*>::const_iterator it = m_BlockAddr.begin(); it != m_BlockAddr.end(); ++it)
{
if(bp >= *it && bp < *it + m_NodeSize * m_BlockCount)
{
assert(((byte_t*)p - *it) % m_NodeSize == 0);
checkflag = true;
break;
}
}
assert(checkflag);
#endif
// 调用析构函数
p->~T();
// 将内存回收到内存池
if(m_pFreeHead )
*(byte_t**)m_pFreeHead = bp;
m_pFreeHead = bp;
p = NULL;
}
public:
/// @brief 该内存池可分配的每个节点的大小
size_t NodeSize()const{return m_NodeSize;}
private:
/// @brief 创建一个新的Block
void AddNewBlock()
{
// 分配内存
byte_t* pBuf = new byte_t[m_NodeSize * m_BlockCount];
// 登记该次分配
m_BlockAddr.push_back(pBuf);
// 将新内存串成空闲链表
byte_t* p = pBuf;
for(size_t i = 0; i < m_BlockCount - 1; i++, p += m_NodeSize)
*(byte_t**)p = (p + m_NodeSize);
*(byte_t**)p = m_pFreeHead;
// 更新空闲链头指针
m_pFreeHead = pBuf;
}
private:
size_t m_NodeSize; ///< 每个内存Node的大小(字节)
size_t m_BlockCount; ///< 每个Block中包含的Node的个数
byte_t* m_pFreeHead; ///< 未使用内存的头指针
std::vector<byte_t*> m_BlockAddr; ///< 该池占用的所有Block的头指针
};
/// @brief 自适应内存池实现
class CMemoryPool
{
typedef unsigned char byte_t;
public:
CMemoryPool()
{
}
~CMemoryPool()
{
for(std::map<size_t, CFixSizeMemoryPool*>::const_iterator it = m_poolList.begin(); it != m_poolList.end(); ++it)
{
delete it->second;
}
m_poolList.clear();
}
public:
bool AddSubPool(size_t size, size_t nodeCountInBlock)
{
if(ExistSubPool(size))
return false;
m_poolList[size] = new CFixSizeMemoryPool(size, 0, nodeCountInBlock);
return true;
}
bool ExistSubPool(size_t size)const
{
return m_poolList.find(size) != m_poolList.end();
}
public:
/// @brief 原生的内存分配。如果用于对象,请注意调用构造函数
void* RawAlloc(size_t size)
{
CFixSizeMemoryPool* pool = FindSubPool(size);
if(pool)
return pool->RawAlloc();
else
{
byte_t* p = new byte_t[size];
#ifdef _DEBUG
std::pair<std::set<void*>::iterator, bool> iret = m_notPoolList.insert(p);
assert(iret.second);
#endif
return p;
}
}
template<typename T>
T* Alloc()
{
return ::new(Alloc(sizeof(T))) T();
}
template<typename T>
void Free(T* p)
{
CFixSizeMemoryPool* pool = FindSubPool(sizeof(T));
if(pool)
pool->Free(p);
else
{
#ifdef _DEBUG
size_t eret = m_notPoolList.erase(p);
assert(eret == 1);
#endif
p->~T();
delete[] (byte_t*)p;
}
}
private:
CFixSizeMemoryPool* FindSubPool(size_t size)
{
std::map<size_t, CFixSizeMemoryPool*>::iterator it = std::lower_bound(m_poolList.begin(), m_poolList.end(), std::map<size_t, CFixSizeMemoryPool*>::value_type(size, NULL));
if(it != m_poolList.end())
{
assert(it->first >= size);
return it->second;
}
return NULL;
}
private:
std::map<size_t, CFixSizeMemoryPool*> m_poolList;
#ifdef _DEBUG
std::set<void*> m_notPoolList;
#endif
};
#include <iostream>
using namespace std;
void main()
{
CFixSizeMemoryPool pool(sizeof(int), CMathUtility::UpBoundTo(7, 8), 1);
int* p = pool.Alloc<int>();
*p = 9;
cout << *p << endl;
pool.Free(p);
cout << p << endl;
}
评论