一个完善的小内存管理系统.
支持内存池和对象池.
我们知道,在频繁的分配很小的内存,或者一些小的对象的时候,很容易造成内存岁片,而且速度也很慢。前段时间做RenderQueque中的Object排序的时候,生成了大量的临时对象(new 出来的),速度非常慢。只有350FPS。当使用内存池后,速度上升到了520fps。其中的速度差距可见一斑啊。
以下的是我在工程中使用的Mempool。基本是抄袭了loki的算法。内存管理器的其他的部分,可以见我的BLog中其他的文章,有连接。
/*
MemPool.h
*/
#ifndef __MEM_POOL_H__
#define __MEM_POOL_H__
#include <vector>
#define DEFUALT_CHUNK_SIZE 8192
using namespace std;
namespace DGE
{
class MemPool
{
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//一块内存.内存块的大小为,blockSize * blocks.
class MemChunck
{
friend class MemPool;
bool init(size_t blockSize, unsigned short blocks);
void reset(size_t blockSize, unsigned short blocks);
void release();
void* alloc(size_t blockSize);
void dealloc(void* p, size_t blockSize);
bool is_ptr(void* p,size_t blockSize, unsigned short blocks);
private://成员
//内存块的地址
unsigned char* m_pData;
//第一个可用块,一个可用块的大小是由blockSize指定的.
//所以说一个MemChunck的大小是 blockSize * blocks
unsigned short m_firstAvailableBlock;
unsigned short m_blocksAvailable;
};
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public:
/*
创建一个MemPool
*/
MemPool(){}
MemPool(size_t block_size, size_t block_reserved);
bool init(size_t block_size, size_t block_reserved);
void clear();
void clear_unused();
//----------------------------------------------------
//为这个MemPool保留多少个字节的空间
//----------------------------------------------------
void reserve(size_t block_reserved);
//----------------------------------------------------
//释放没有用过的空间.
//----------------------------------------------------
size_t unused_block();
//----------------------------------------------------
//查看还有多少空间可以用
//----------------------------------------------------
size_t capacity();
//----------------------------------------------------
//分配一个内存和释放一个内存
//----------------------------------------------------
void* alloc();
void dealloc(void* p);
//----------------------------------------------------
//判断一个指针是不是由这个Pool分配的。
//----------------------------------------------------
bool is_ptr(void* p);
/**
内存池塘需要记录的信息
1: 每一个块的大小,即FixedAlloctor能分配的大小. 当m_blockSize不能为1.
2: 每个MemChunck中,Block的个数.
3: 内存池中,空闲的块的个数
*/
private:
size_t m_blockSize; //每一个块的大小,即FixedAlloctor能分配的大小. 当m_blockSize不能为1.
size_t m_blocksPerChunk; //每个MemChunck中,Block的个数.
size_t m_avaliableBlocks; // 内存池中,空闲的块的个数
typedef std::vector<MemChunck> MemChunks;
MemChunks m_Chuncks;
int m_lastChunk;
//void* m_pDealloc;
//********************************************************
//
//********************************************************
#ifdef _DEBUG
template<typename T> void diagnostic(T& out)
{
}
#endif
//-------------------------------------------------------
//End of the class MemPool
};
}
#endif
/*
MemPool.cpp
*/
#include "MemPool.h"
#include <cassert>
#include <algorithm>
using namespace std;
/******
内存池分配器.
也就是一个固定大小的内存分配器.
分配算法为自创部分,外加Loki的启发,所以现在算法基本为Loki中的FixedAlloctor
******/
/*
m_pData---> [X X X X X ...]
第一个可用块 --> [3 | _____ ...]
[X X X X X ...]
[ | _____ ...]
[X X X X X ...]
*/
namespace DGE
{
bool MemPool::MemChunck::init(size_t blockSize, unsigned short blocks)
{
assert(blockSize > 0);
assert(blocks > 0);
// Overflow check
assert((blockSize * blocks) / blockSize == blocks);
m_pData = (unsigned char*) malloc(blockSize * blocks);
if(m_pData == NULL)
return false;
reset(blockSize, blocks);
return true;
}
void* MemPool::MemChunck::alloc(size_t blockSize)
{
if (!m_blocksAvailable) return 0;
//检查内存是不是依然对齐的
assert((m_firstAvailableBlock * blockSize) / blockSize == m_firstAvailableBlock);
//把第一个可用返回给拥护
unsigned char* pResult = m_pData + (m_firstAvailableBlock * blockSize);
m_firstAvailableBlock = *pResult;
-- m_blocksAvailable;
return pResult;
}
void MemPool::MemChunck::dealloc(void* p, size_t blockSize)
{
assert(p >= m_pData);
unsigned char* toRelease = static_cast<unsigned char*>(p);
//内存对齐检查
assert((toRelease - m_pData) % blockSize == 0);
//把释放掉的块加入到表头里.新建一个表头,表头下一个块指向原来的第一个可用块
* ((unsigned short*)toRelease) = m_firstAvailableBlock;
//第一个可用块指向表头
m_firstAvailableBlock = static_cast<unsigned char>( (toRelease - m_pData) / blockSize ) ;
//块对齐检查
assert(m_firstAvailableBlock == (toRelease - m_pData) / blockSize);
++ m_blocksAvailable;
}
void MemPool::MemChunck::reset(size_t blockSize, unsigned short blocks)
{
assert(blockSize > 0);
assert(blocks > 0);
//诣出检查
assert((blockSize * blocks) / blockSize == blocks);
m_firstAvailableBlock = 0;
m_blocksAvailable = blocks;
//填充内存块的链
unsigned short i = 0;
unsigned char* p = m_pData;
for (; i != blocks; p += blockSize)
{
unsigned short * pNext =(unsigned short*) p;
*pNext = ++i;
}
}
void MemPool::MemChunck::release()
{
free((void*)m_pData);
}
bool MemPool::MemChunck::is_ptr(void* p,size_t blockSize, unsigned short blocks)
{
if( p < m_pData) return false;
//内存不在这个里面。也不是他分配的。
if( p > m_pData + blockSize * blocks) return false;
//指针没在blockSize边界上对齐.肯定不是由这个MemChunck分配的
if( ((unsigned char*)p - m_pData)%blockSize != 0) return false;
return true;
}
//======================================================================================
// 以下为MemPool的类.
// 函数的实现.
//======================================================================================
MemPool::MemPool(size_t block_size, size_t block_reserved)
{
init(block_size,block_reserved);
}
bool MemPool::init(size_t block_size, size_t block_reserved)
{
m_blockSize = block_size;
m_blocksPerChunk = DEFUALT_CHUNK_SIZE / block_size;
m_avaliableBlocks = 0;
size_t nChuncks = (block_reserved + 1 ) / m_blocksPerChunk;
for(size_t i = 0 ; i < nChuncks ; i ++ )
{
MemChunck chunck;
if( chunck.init(m_blockSize,(unsigned short)m_blocksPerChunk) == false)
return false;
m_Chuncks.push_back(chunck);
m_avaliableBlocks += m_blocksPerChunk;
}
m_lastChunk = 0;
return true;
}
void MemPool::clear()
{
size_t nChuncks = m_Chuncks.size();
for(size_t i = 0 ; i < nChuncks ; i ++ )
{
m_Chuncks[i].release();
}
m_avaliableBlocks = 0;
}
void MemPool::clear_unused()
{
MemChunks::iterator i = m_Chuncks.end();
size_t n = m_Chuncks.size();
while( (n--)!=0)
{
--i;
if(i->m_blocksAvailable == m_blocksPerChunk)
{
i->release();
m_Chuncks.erase(i);
}
}
m_lastChunk = 0;
}
//----------------------------------------------------
//为这个MemPool保留多少个字节的空间
//----------------------------------------------------
void MemPool::reserve(size_t block_reserved)
{
if(m_avaliableBlocks >= block_reserved)
return ;
size_t nChuncks = (block_reserved - m_avaliableBlocks + 1) / m_blocksPerChunk;
for(size_t i = 0 ; i < nChuncks ; i ++ )
{
MemChunck chunck;
if( chunck.init(m_blockSize,(unsigned short)m_blocksPerChunk) == false)
return ;
m_Chuncks.push_back(chunck);
m_avaliableBlocks += m_blocksPerChunk;
}
}
//----------------------------------------------------
//释放没有用过的空间.
//----------------------------------------------------
size_t MemPool::unused_block()
{
return m_avaliableBlocks;
}
//----------------------------------------------------
//查看还有多少空间可以用
//----------------------------------------------------
size_t MemPool::capacity()
{
return m_Chuncks.size() * m_blocksPerChunk * m_blockSize;
}
//-------------------------------------------- --------
//分配一个内存和释放一个内存
//----------------------------------------------------
void* MemPool::alloc()
{
//先用最后一次分配的MemChunck来分配.
//如果最后一个块还有,就返回.
void * ret = m_Chuncks[m_lastChunk].alloc(m_blockSize);
if(ret) {m_avaliableBlocks --; return ret;}
size_t nChuncks = m_Chuncks.size();
//找一个有空块的MemChunck
for(size_t i = 0 ; i < nChuncks ; i ++ )
{
if(m_Chuncks[i].m_blocksAvailable > 0)
{
//把最后一个分配块的游标指向有空闲的块.
//可用块的计数减少,并分配一个块出去
m_lastChunk = (int)i;
m_avaliableBlocks --;
return m_Chuncks[m_lastChunk].alloc(m_blockSize);
}
}
//建立一个新的Block,放到里面.
m_Chuncks.push_back( MemChunck() );
m_lastChunk = (int)nChuncks;
//如果块初始化失败,则表示没有内存了。返回空.表示失败
if( false == m_Chuncks[nChuncks].init(m_blockSize,(unsigned short)m_blocksPerChunk))
return NULL;
//新建立了一个块.放到最后
m_avaliableBlocks += (m_blocksPerChunk - 1);
return m_Chuncks[m_lastChunk].alloc(m_blockSize);
}
void MemPool::dealloc(void* p)
{
{
if(m_Chuncks[m_lastChunk].is_ptr(p,m_blockSize,(unsigned short)m_blocksPerChunk) == true)
{
m_Chuncks[m_lastChunk].dealloc(p,m_blockSize);
m_avaliableBlocks ++;
return ;
}
size_t nChuncks = m_Chuncks.size();
for(size_t i = 0 ; i < nChuncks ; i ++ )
{
if(m_Chuncks[i].is_ptr(p,m_blockSize,(unsigned short)m_blocksPerChunk) == true)
{
//当前释放了一个内存.那么这个Chunck肯定是有内存可以用的。
m_lastChunk =(int) i;
m_Chuncks[m_lastChunk].dealloc(p,m_blockSize);
m_avaliableBlocks ++;
return ;
}
}
return ;
}
}
//----------------------------------------------------
//判断一个指针是不是由这个Pool分配的。
//----------------------------------------------------
bool MemPool::is_ptr(void* p)
{
size_t nChuncks = m_Chuncks.size();
for(size_t i = 0 ; i < nChuncks ; i ++ )
{
if(m_Chuncks[i].is_ptr(p,m_blockSize,(unsigned short)m_blocksPerChunk) == true)
{
return true;
}
}
return false;
}
}
/*
ObjectPool.h
*/
#ifndef __OBJECT_POOL__
#define __OBJECT_POOL__
#include "MemPool.h"
using namespace DGE;
template <typename T>
class CObjectPool
{
MemPool m_MemPool;
friend T;
public:
CObjectPool(int ObjectReserve = 8192*8):m_MemPool(sizeof(T),ObjectReserve){}
~CObjectPool(){m_MemPool.clear();}
void* createObj(){return (void*)m_MemPool.alloc();}
void destoryObj(void*p){m_MemPool.dealloc(p);}
};
#define DECL_OBJECT_POOL(Type) /
static CObjectPool<Type> m_ObjPool;/
void* operator new(size_t t){ return m_ObjPool.createObj(); }/
void operator delete(void* p) { m_ObjPool.destoryObj(p); }/
void realse_all_object(){m_ObjPool.m_MemPool.clear();} /
#define IMP_OBJECT_POOL(Type,ObjectReserve)/
CObjectPool<Type> Type::m_ObjPool(ObjectReserve);/
#endif