内存池(MemPool)技术详解 转
转载声明:本文转自csdn博客,许式伟著,链接:http://blog.csdn.net/xushiweizh/archive/2006/11/22/1402967.aspx
小狼注:上次也写了一个简单的内存池,是使用STL的deque来管理的,实现起来比较简单,不过有个缺点就是只能固定分配大小,所以需要根据经验值事先分配内存大小,然后把内存再次划分为等大的小的内存供使用。
概述
内存池(MemPool)技术备受推崇。我用google搜索了下,没有找到比较详细的原理性的文章,故此补充一个。另外,补充了boost::pool组件与经典MemPool的差异。同时也描述了MemPool在sgi-stl/stlport中的运用。
经典的内存池技术
{
private:
const int m_nMemBlockSize;
const int m_nItemSize;
struct _FreeNode {
_FreeNode* pPrev;
};
struct _MemBlock {
_MemBlock* pPrev;
_FreeNode data[m_nMemBlockSize/m_nItemSize];
};
_MemBlock* m_pMemBlockHeader;
_FreeNode* m_pFreeNodeHeader;
public:
MemPool(int nItemSize, int nMemBlockSize = 2048)
: m_nItemSize(nItemSize), m_nMemBlockSize(nMemBlockSize),
m_pMemBlockHeader(NULL), m_pFreeNodeHeader(NULL)
{
}
};
申请内存过程
{
if (m_pFreeNodeHeader == NULL)
{
const int nCount = m_nMemBlockSize/m_nItemSize;
_MemBlock* pNewBlock = new _MemBlock;
pNewBlock->data[0].pPrev = NULL;
for (int i = 1; i < nCount; ++i)
pNewBlock->data[i].pPrev = &pNewBlock->data[i-1];
m_pFreeNodeHeader = &pNewBlock->data[nCount-1];
pNewBlock->pPrev = m_pMemBlock;
m_pMemBlock = pNewBlock;
}
void* pFreeNode = m_pFreeNodeHeader;
m_pFreeNodeHeader = m_pFreeNodeHeader->pPrev;
return pFreeNode;
}
- 在自由内存结点链表(FreeNodeList)非空。
在此情况下,Alloc过程只是从链表中摘下一个结点的过程。
- 否则,意味着需要一个新的内存块(MemBlock)。
这个过程需要将新申请的MemBlock切割成多个Node,并把它们串起来。
MemPool技术的开销主要在这。
释放内存过程
{
_FreeNode* pNode = (_FreeNode*)p;
pNode->pPrev = m_pFreeNodeHeader;
m_pFreeNodeHeader = pNode;
}
性能分析
boost::pool
boost::pool是内存池技术的变种。主要的变化如下:
- MemBlock改为非固定长度(MemBlockSize),而是:第1次申请时m_nItemSize*32,第2次申请时m_nItemSize*64,第3次申请时m_nItemSize*128,以此类推。不采用固定的MemBlockSize,而采用这种做法预测模型(是的,这是一种用户内存需求的预测模型,其实std::vector的内存增长亦采用了该模型),是一个细节上的改良。
- 增加了ordered_free(void* p) 函数。
ordered_free区别于free的是,free把要释放的结点挂到自由内存链表(FreeNodeList)的开头,ordered_free则假设FreeNodeList是有序的,因此会遍历FreeNodeList把要释放的结点插入到合适的位置。
我们已经看到,free的复杂度是O(1),非常快。但请注意ordered_free是比较费的操作,其复杂度是O(N)。这里N是FreeNodeList的大小。对于一个频繁释放/申请的系统,这个N很可能是个大数。这个boost描述得很清楚:http://www.boost.org/libs/pool/doc/interfaces/pool.html
注意:不要认为boost提供ordered_free是多此一举。后文我们会在讨论boost::object_pool时解释这一点。
基于内存池技术的通用内存分配组件
sgi-stl把内存池(MemPool)技术进行发扬光大,用它来实现其最根本的allocator。
注意
以上代码属于伪代码(struct _FreeNode、_MemBlock编译通不过),并且去除了出错处理。
评论