手写内存池

概要

纯c和cpp实现的简单内存池,均是申请固定大小的内存块

内存池使用以及作用

内存池技术是一种优化内存管理的方法,它通过预先分配一块连续的内存空间,可以将其设置成固定大小块,也可以随机分配(本文是采用固定大小内存块)。之后在程序中使用这些内存块,这样可以减少频繁的动态内存分配和释放操作,从而提高性能和效率。

内存块的作用主要有两点:一是使用内存池技术可以避免内存碎片化问题,并减少了系统调用次数,节省了时间开销。二是内存池还可以提供更好的局部性,因为相邻的对象通常在物理上也是相邻的,这有助于提高缓存命中率,能够提升分配和归还的速度。

纯c实现内存池

typedef struct mempool_s
{
    int block_size;
    int free_count;

    char* free_ptr;
    char* mem;
}mempool_t;

内存池结构体,包括内存池的固定块大小,空闲块个数,指向空闲区域的头指针以及指向整个内存池的指针。

主要接口

int mp_init(mempool_t* m,int size){
    if(!m)return -1;
    if(size<16)size=16;
    m->block_size=size;
    m->mem=(char*)malloc(MEM_PAGE_SIZE);
    if(!m->mem)return -1;
    m->free_ptr=m->mem;
    m->free_count=MEM_PAGE_SIZE/size;
    int i=0;
    char* ptr=m->free_ptr;
    for(;i<m->free_count;++i){
        *(char**)ptr=ptr+size;
        ptr+=size;
    }
    *(char**)ptr=NULL;
}
 void mp_destory(mempool_t* m){
    if(!m||!m->mem)return;
    free(m->mem);
}
void* mp_malloc(mempool_t* m){
   if(!m||m->free_count==0)return NULL;
   void* ptr=m->free_ptr;
   m->free_ptr=*(char**)ptr;
   m->free_count--;
   return ptr;
}
void mp_free(mempool_t* m,void* ptr){
    *(char**)ptr=m->free_ptr;
    m->free_ptr=(char*)ptr;
    m->free_count++;
}

这是实现内存池功能的四个接口,分别是初始化内存池,销毁内存池,分配内存块,释放内存块。代码看着蛮清晰易懂的,唯一的难点可能是*(char**)这个指针的操作,以init函数中的为例:先是拿到指向空余内存块的指针,然后循环内存块,将ptr指针强转为二级指针再解引用,也就是每个内存块中的首部包含了一个char*,指向下一个节点,从而形成了一个链表。

测试

int main(){
    mempool_t m;
    mp_init(&m,32);
    void* p1=mp_malloc(&m);
    printf("mp_malloc:%p\n",p1);
    void* p2=mp_malloc(&m);
    printf("mp_malloc:%p\n",p2);

    void* p3=mp_malloc(&m);
    printf("mp_malloc:%p\n",p3);

    void* p4=mp_malloc(&m);
    printf("mp_malloc:%p\n",p4);
    
    mp_free(&m,p2);
     void* p5=mp_malloc(&m);
    printf("mp_malloc:%p\n",p5);
}

测试结果
在这里插入图片描述
结果是合理的。

cpp实现简单内存池

class mempool
{
public:
   int m_size;
   int m_count;
   static char* m_pool; //起始地址

  static bool initpool(){
    m_pool=(char*)malloc(18);
    if(!m_pool)return false;
    memset(m_pool,0,18);
    cout<<"内存池的起始地址是"<<(void*)m_pool<<endl;
    return true;
   }

  static void freepool(){
    if(!m_pool)return;
    free(m_pool);
    cout<<"内存池以释放"<<endl;
   }

   mempool(int size,int count){
    m_size=size;
    m_count=count;
    cout<<"调用了mempool的构造函数"<<endl;
   }
   ~mempool(){
    cout<<"调用了mempool的析构函数"<<endl;
   }
   void* operator new(size_t size){
    if(m_pool[0]==0){
        cout<<"分配第一块内存:"<<(void*)(m_pool+1)<<endl;
        m_pool[0]=1;
        return m_pool+9;
    }
    if(m_pool[9]==0){
        cout<<"分配第一块内存:"<<(void*)(m_pool+1)<<endl;
        m_pool[9]=1;
        return m_pool+9;
    }
    void* ptr=malloc(size);
    cout<<"申请到的内存地址是:"<<ptr<<endl;
    return ptr;
   }

   void operator delete(void* ptr){
        if(ptr==0)return;
        if(ptr==m_pool+1)
        {
            cout<<"释放了第一块内存"<<endl;
            m_pool[0]=0;
            return;
        }
        if(ptr==m_pool+9)
        {
            cout<<"释放了第二块内存"<<endl;
            m_pool[9]=0;
            return;
        } 
        free(ptr);
   }

};
char* mempool::m_pool=0;

这是内存池类的实现,其中重载了delete和new运算符(为一个类重载delete/new运算符时,虽然不必显示声明static,但是仍是在创建静态成员函数)。所以,m_poll也需要定义为static成员变量,并在类外初始化。

当内存池用完了的时候,一般有三种方法:1.扩展内存池 2.直接向系统申请内存 3.返回空地址,具体看情况定,本文使用的第二种。

测试

int main(){

    if(mempool::initpool()==false){
        cout<<"初始化失败"<<endl;
    }
        mempool* m1=new mempool(8,1);
        cout<<"m1的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;

        mempool* m2=new mempool(8,1);
        cout<<"m2的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;

        mempool* m3=new mempool(8,1);
        cout<<"m3的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;
        
        delete m1;
        mempool* m4=new mempool(8,1);
        cout<<"m4的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;
        delete m2;
        delete m3;
        delete m4;
        mempool::freepool(); 
}

测试结果
在这里插入图片描述
结果是合理的。
到这,一个简单的内存池模型就完成了。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐