内存池(MemPool)技术详解

原创 2006年11月22日 00:44:00
本文已经迁移到: http://cpp.winxgui.com/cn:dive-into-memory-pool

概述

内存池(MemPool)技术备受推崇。我用google搜索了下,没有找到比较详细的原理性的文章,故此补充一个。另外,补充了boost::pool组件与经典MemPool的差异。同时也描述了MemPool在sgi-stl/stlport中的运用。

 

经典的内存池技术

 
 
经典的内存池(MemPool)技术,是一种用于分配大量大小相同的小对象的技术。通过该技术可以极大加快内存分配/释放过程。下面我们详细解释其中的奥妙。
 
经典的内存池只涉及两个常量:MemBlockSize、ItemSize(小对象的大小,但不能小于指针的大小,在32位平台也就是不能小于4字节),以及两个指针变量MemBlockHeader、FreeNodeHeader。开始,这两个指针均为空。
 
class MemPool
{
private:
    const int m_nMemBlockSize;
    
const int m_nItemSize;

    struct _FreeNode {
        _FreeNode
* pPrev;
        BYTE data[m_nItemSize - sizeof(_FreeNode*)];
    };

    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)
   {
   }
};
 
 
其中指针变量MemBlockHeader是把所有申请的内存块(MemBlock)串成一个链表,以便通过它可以释放所有申请的内存。FreeNodeHeader变量则是把所有自由内存结点(FreeNode)串成一个链。
 
这段话涉及两个关键概念:内存块(MemBlock)自由内存结点(FreeNode)。内存块大小一般固定为MemBlockSize字节(除去用以建立链表的指针外)。内存块在申请之初就被划分为多个内存结点(Node),每个Node大小为ItemSize(小对象的大小),计MemBlockSize/ItemSize个。这MemBlockSize/ItemSize个内存结点刚开始全部是自由的,他们被串成链表。我们看看申请/释放内存过程,就很容易明白这样做的目的。
 

申请内存过程

代码如下:
 
void* MemPool::malloc()    // 没有参数
{
    
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技术的开销主要在这。
     

释放内存过程

 代码如下:
void MemPool::free(void* p)
{
    _FreeNode
* pNode = (_FreeNode*)p;
    pNode
->pPrev = m_pFreeNodeHeader;
    m_pFreeNodeHeader 
= pNode;
}
 
释放过程极其简单,只是把要释放的结点挂到自由内存链表(FreeNodeList)的开头即可。
 
 
 

性能分析

MemPool技术申请内存/释放内存均极其快(比AutoFreeAlloc慢)。其内存分配过程多数情况下复杂度为O(1),主要开销在FreeNodeList为空需要生成新的MemBlock时。内存释放过程复杂度为O(1)。
 
 
 
 

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。
 
 
其大体的思想是,建立16个MemPool,<=8字节的内存申请由0号MemPool分配,<=16字节的内存申请由1号MemPool分配,<=24字节的内存有2号MemPool分配,以此类推。最后,>128字节的内存申请由普通的malloc分配。
 
 
 
 

注意


以上代码属于伪代码(struct _FreeNode、_MemBlock编译通不过),并且去除了出错处理。

图解dpdk mempool 对象

一、文件组织 rte_mempool.h:mempool类的属性、方法 rte_mempool.c:mempool对象的创建实现、mempool对象与ring对象(默认)的联系。 rte_mempo...

DPDK 内存管理(二)(rte_mempool 内存管理)

DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发;一个是rte_malloc,主要为应用程序提供内存使用接口。本文讨论rte_mempool。rte_me...

内存池的实现

基本的架构设计: 基本运行结果:$ ./mem_pool ...UseBlocks[0] =(nil),FreeBlocks[0] =(nil) ...UseBlocks[1] =(nil),Fr...

内存池介绍与经典内存池的实现

1.默认内存管理函数的不足利用默认的内存管理函数new/delete或malloc/free在堆上分配和释放内存会有一些额外的开销。系统在接收到分配一定大小内存的请求时,首先查找内部维护的内存空闲块表...

高效内存池的设计方案[C语言]

分类: 设计思路2012-11-18 02:18 1257人阅读 评论(6) 收藏 举报 目录(?)[+] 一、前言概述 本人在转发的博文《内存池的设计和实现...
  • pi9nc
  • pi9nc
  • 2013年01月11日 22:29
  • 7303

C语言实现内存池

什么是内存池,这里简单介绍一下(不做详细说明),内存池技术是一种用于分配大量大小相同的小对象的技术,通过该技术可以极大加快内存分配/释放过 程。其原理是先申请一大块内存,然后分成若干个大小相等的小块...

内存池设计与实现

1. 内存池设计1.1 目的 在给定的内存buffer上建立内存管理机制,根据用户需求从该buffer上分配内存或者将已经分配的内存释放回buffer中。1.2 要求 尽量减少内存碎片,平均效率高于C...

内存池——第一章 几种常用的内存池技术

几乎所有应用程序中都会有内存的分配和释放,而频繁的分配和释放内存无疑会产生内存碎片,降低系统性能,尤其对性能要求较高的程序比较明显。下面介绍几种常见的内存池技术。     一  环形缓存 ...

内存池技术介绍

 看到一篇关于内存池技术的介绍文章,受益匪浅,转贴至此。  原贴地址:http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html 6...

C++中我们为什么提倡使用内存池技术?

1.什么是内存池技术及为什么要设计自己的内存池?     通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定, 当频繁使用时会造成大量的内存碎片...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:内存池(MemPool)技术详解
举报原因:
原因补充:

(最多只允许输入30个字)