`

内存池技术详解

阅读更多

 

概述

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

注意


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

 

分享到:
评论

相关推荐

    经典的内存池技术经典的内存池技术

    ### 经典内存池技术详解 #### 一、引言 经典的内存池技术是一种高效的内存管理方式,尤其适用于需要频繁创建和销毁大量相同大小小对象的场景。它通过预分配和重用内存来减少内存分配与释放所带来的开销,从而显著...

    内存池例子-有代码和解析

    ### 内存池技术详解与实现案例 #### 一、内存池的概念与作用 内存池是一种数据结构,用于管理程序运行过程中使用的内存资源。通过内存池可以有效地减少内存分配和释放带来的性能开销,同时避免内存碎片的问题。...

    Kmalloc 共享内存池技术架构详解-KaiwuDB

    【Kmalloc 共享内存池技术架构详解】 Kmalloc 是 KaiwuDB 为优化内存管理设计的一种共享内存池技术,其目标是提高内存利用率并解决传统内存管理中的问题,如内存碎片、进程间数据共享效率低以及内存异常检测。本文...

    嵌入式Linux内存与性能详解-史子旺

    接着,性能优化方面,可能会讲解如何使用内存池技术来预先分配内存,避免频繁的动态分配导致的性能瓶颈。此外,内存碎片问题及其解决方法,如内存对齐、紧凑等也是讨论的重点。书中可能还会介绍如何使用工具如`free`...

    GlusterFS 之内存池(mem-pool)实现原理及代码详解

    其中,内存池技术(mem-pool)是GlusterFS内部优化中的一个重要组成部分,旨在提高内存管理效率。 #### 二、内存池技术概述 内存池是一种常用的数据结构,用于管理相同大小的对象集合。它通过预分配一定量的内存,...

    一种自适应变长块内存池

    ### 一种自适应变长块内存池的知识点详解 #### 一、背景与引入 在高性能计算和网络处理领域,特别是在处理大量不确定长度的数据时,内存管理成为一个关键的技术挑战。传统的方法,如直接使用`malloc`和`free`进行...

    Android优化技术详解

    Android系统采用Dalvik/ART虚拟机进行运行时环境支持,内存优化主要包括减少内存泄漏、避免过度绘制和合理使用内存池。开发者应学习使用MAT工具分析内存快照,找出内存泄漏问题,并通过避免长时间持有强引用和使用...

    Oracle内存参数调优技术详解

    Oracle 内存参数调优技术详解 Oracle 内存参数调优技术是指在 Oracle 实例中调整内存参数以提高数据库性能的技术。 Oracle 实例由内存结构和进程结构两部分组成。内存结构包括 SGA(系统全局区)和 PGA(程序全局区...

    Tomcat与Java_Web开发技术详解3.pdf

    4. **数据库连接池**:为了提高数据库访问效率,通常会使用连接池技术来管理数据库连接。Tomcat自带的JDBC连接池可以方便地管理和复用数据库连接资源。 #### 四、Java Web开发高级技术 随着Java Web开发的发展,...

    内存池的介绍与设计详解

    内存池是一种内存管理技术,主要用于优化动态内存分配的效率和减少内存碎片。它预先分配一大块连续的内存区域,然后将其划分为多个固定大小的小块,这些小块称为内存单元。内存池的主要思想是集中管理和复用内存,...

    内存池管理

    ### 内存池管理知识点详解 #### 一、C++程序性能优化概述 根据所提供的信息来看,本书聚焦于C++程序的性能优化方面,并通过四个篇章深入探讨了多个与优化相关的主题。首先需要理解的是,C++作为一种强大的编程语言...

    Windows驱动开发技术详解(PDF)

    《Windows驱动开发技术详解》是一本专为对Windows操作系统内核和驱动程序开发感兴趣的读者精心编写的指南。这本书深入浅出地阐述了Windows驱动程序的开发过程,旨在帮助读者掌握驱动程序的基础知识、设计原理以及...

    Windows驱动开发技术详解(珍藏版)

    6. **内存管理**:探讨驱动程序中的内存分配与释放策略,包括非分页池和分页池的使用,以及内存泄漏检测。 7. **同步与并发控制**:讲解驱动程序中的线程同步技术,如事件、信号量、互斥体,以及IRQL级别的同步机制...

    【C++项目设计】高并发内存池.zip

    本项目实现的是一个高并发的内存池,它的原型是Google的一个开源项目tcmalloc,tcmalloc全称Thread-Caching Malloc,即线程缓存的malloc,实现了高效的多线程内存管理,用于替换系统的内存分配相关函数malloc和free...

    Oracle内存架构详解

    - **流池(Streams Pool)**: 专为Oracle GoldenGate Streams功能设计的内存池。 - **数据字典缓存(Data Dictionary Cache)**: 存储了数据库对象的元数据,包括表、索引、视图等的定义信息。 ##### SGA的组成部分...

    内存碎片处理技术

    5. **内存池技术**:通过预先分配一大块内存作为内存池,然后从中分配固定大小的内存块,可以有效减少内部碎片。 #### 五、内存碎片的测量与评估 衡量内存碎片程度的常用方法是计算空闲内存的最大连续块与所有空闲...

    C/C++内存管理深入详解

    2. 堆内存:相对于栈而言,堆是一个更大的内存池,它不是自动分配和回收的,而是通过程序员控制。程序员可以使用new和delete(在C++中)或malloc和free(在C中)来动态分配和释放内存。堆上的内存分配和释放比较灵活...

Global site tag (gtag.js) - Google Analytics