内存池设计(四)

   memorypool 的设计  相比于 memoryblock 的设计就相对简单一点 主要是对其域初始化 其代码如下

   

memorypool(int _ngrowsize=10,int _ninitsize=3)
{
    cout<<"-----------------调用内存池的构造函数---------------"<<endl;
    ninitsize=_ninitsize;  // 首块长度
    ngrowsize=_ngrowsize;   //后续块长度
    pblock=NULL; // 链表指针置为 null
    nunitsize=sizeof(T);  // 定义存储单位大小
    if(sizeof(T)>4)///调整存储单位的大小
        nunitsize=(sizeof(T)+(MEMPOOL_ALIGNMENT-1)) & ~(MEMPOOL_ALIGNMENT-1);// 返回值为8的倍数 所谓的内存对齐
    else if(sizeof(T)<2)
        nunitsize=2;
    else
        nunitsize=4;
}

   memorypool 的析构函数如下

   

~memorypool()
{
    memoryblock<T>*pmyblock=pblock;
    while(pmyblock!=NULL)
    {
        pmyblock=pmyblock->pnext;
        delete(pmyblock);
    }
    cout<<"--------------------调用内存池的析构函数-------------------"<<endl;
}

   在 memorypool中 主要操作就是用于向内存池请求存储单位的函数 allocate() ,这也是内存池向用户提供的主要服务。从程序的执行任务看,该函数的工作就是遍历内存块,找到 nfree 大于0 ,即有空闲单位的内存块,并从其上分配存储单位。然后将内存块 memoryblock 表中域 nfree 减一,并修改空闲单位链表头指针 nfirst 的值。

   其代码如下

   

void *allocate(size_t num)
{
    for(int i=0;i<num;++i)
    {
    if(NULL==pblock)
    {
        ///创建首内存块
        pblock=(memoryblock<T>*)new (nunitsize,ninitsize)
        memoryblock<T>(nunitsize,ninitsize);
        return (void*)pblock->adata;///返回内存块中数据元素存储区指针
    }
    ///为内存寻找符合条件的内存块
    memoryblock<T>*pmyblock=pblock;
    while(pmyblock!=NULL&&0==pmyblock->nfree)
        pmyblock=pmyblock->pnext;
    if(pmyblock!=NULL)
    {
        cout<<"找到内存空间 first= "<<pmyblock->nfirst<<endl;
        ///找到后进行内存分配
        char *pfree=pmyblock->adata+pmyblock->nfirst*nunitsize;
        pmyblock->nfirst=*((unsigned short*)pfree);
        pmyblock->nfree--;
        ///返回找到的存储单位指针
        return (void*)pfree;
    }
    else
    {
        ///没有找到 说明当前内存块已用完
        if(0==ngrowsize)return NULL;
        cout<<" 否则分配新内存块"<<endl;
        //分配一个后续内存块
        pmyblock=(memoryblock<T>*)new(nunitsize,ngrowsize)
        memoryblock<T>(nunitsize,ngrowsize);
        if(NULL==pmyblock)
            return NULL;///失败
        pmyblock->pnext=pblock;
        pblock=pmyblock;
        //返回新内存的的存储区指针
        return (void*)pmyblock->adata;
    }
}
}

       memorypool 的另一个重要函数就是用于释放内存的 free() ,该函数根据 pfree 的值,找到他所在的内存块,然后将他的序号 nfirst 的值(因为他绝对空闲) ,在pfree 的头两个字节写入原来nfirst的值,然后判断 该 块的是否全为 free 方法是检测 nfree*nunitsize==nsize. 若是,则向系统释放内存,若不是,则将该 block放到链表的头部,因为该block上含有空闲的内存单元,这样可以减少分配时遍历链表所消耗的时间。

void free(void *pfree)
{
    //找到p所在的块
    cout<<"释放存储单位内存空间"<<endl;
    memoryblock<T>*pmyblock=pblock;
    memoryblock<T>*preblock=NULL;
    while(pmyblock!=NULL&&(pblock->adata>pfree||pmyblock->adata+pmyblock->nsize))
    {
        preblock=pmyblock;
        pmyblock=pmyblock->pnext;
    }
    //该内存块在被内存池pmyblock 所指向的内存块中
    if(NULL!=pmyblock)
    {
        //1 修改数组链表
        *((unsigned short*)pfree)=pmyblock->nfirst;
        pmyblock->nfirst=(unsigned short)((unsigned long)pfree-(unsigned long)pmyblock->adata)/nunitsize;
        pmyblock->nfree++;
        // 2 判断是否需要向系统释放内存
        if(pmyblock->nsize==pmyblock->nfree*nunitsize)
        {
            //在链表中删除
            delete(pmyblock);
        }
        else
        {
            //将该block 插入队首
            preblock=pmyblock->pnext;
            pmyblock->pnext=pblock;
            pblock=pmyblock;
        }
    }
}

  

原文地址:https://www.cnblogs.com/guoyu1024/p/9607051.html