zoukankan      html  css  js  c++  java
  • 内存池设计(五)

     将以上代码组装,并自己设计累 user 来测试这个内存池

    #include<iostream>
    #define MEMPOOL_ALIGNMENT 8  // 对齐长度
    using namespace std;
    ///内存块及其信息表 memory block-----------------------
    template<typename T>
    struct memoryblock
    {
        int nsize;//该内存块的大小
        int nfree;// 该内存还有多少可分配单位
        int nfirst;//当前可分配的第一个单位序号
        memoryblock *pnext;// 指向下一个内存块
        char adata[1];// 用于标记分配单元开始的位置
        memoryblock(int nunitsize,int nunitamount):nsize(nunitsize * nunitamount),nfree(nunitamount-1),nfirst(1),pnext(NULL)
        // nunitsize 存储单位的大小 即 sizeof(T) nunitamount 内存块规模
        // nfree 空闲存储单位为 nunitamount-1 nfirst 初值为1 pnext指向下一个内存块的指针为NULL
        {
            //为空闲区编号
          char *ppdata=adata;
          cout<<"存储区首指针 ppdate ="<<(int*)ppdata<<endl;
          for(int i=1;i<nunitamount;i++)
          {
              //当前存储单位存储下一个可分配单位的序号
              (*(unsigned short *)ppdata)=i;
              cout<<"下一个可分配单位序号: "<<(int)*ppdata<<endl;
              //移动指针使之指向下一个单位
              ppdata+=nunitsize;
          }
          cout<<"-------------调用内存块的构造函数-------------------"<<endl;
        }
          void *operator new(size_t,int nunitsize,int nunitamount)
          {
              cout<<"分配内存并创建memoryblock 对象"<<endl;
              return ::operator new(sizeof(memoryblock)+nunitsize*nunitamount);
          }
          void operator delete(void *pblock)
          {
              ::operator delete(pblock);
              cout<<"---------------调用内存块的析构函数----------------"<<endl;
          }
    };
    ///内存池信息表
    template<typename T>
    struct memorypool
    {
        int ninitsize;///首块长度
        int ngrowsize;///后续块长度
        int nunitsize;/// 定义存储单位大小
        memoryblock<T>*pblock;
    memorypool(int _ngrowsize=10,int _ninitsize=3)
    {
        cout<<"-----------------调用内存池的构造函数---------------"<<endl;
        ninitsize=_ninitsize;
        ngrowsize=_ngrowsize;
        pblock=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()
    {
        memoryblock<T>*pmyblock=pblock;
        while(pmyblock!=NULL)
        {
            pmyblock=pmyblock->pnext;
            delete(pmyblock);
        }
        cout<<"--------------------调用内存池的析构函数-------------------"<<endl;
    }
    ///用于向内存池请求存储单位的函数,也是内存池向用户提供的主要服务
    ///遍历内存块链表,找到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;
        }
    }
    }
    //free 函数用于释放内存块 该函数根据pfree 的值找到他所在的内存块 然后将它的序号作为nfirst的值(因为他绝对空闲)
    //在pfree 的头两个字节内写入原来nfirst 的值。然后要判断 该block 是否全部为free 方法是检测nfree*nunitsize==size
    // 若是 则向系统释放内存 若不是 则将该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;
            }
        }
    }
    };
    class user
    {
        int s;
        double s1;
        double s3;
    public:
        user(int x):s(x)
        {
            cout<<"-------------------调用 user 的析构函数----------------"<<endl;
        }
        int get()
        {
            return s;
        }
        ~user()
        {
            cout<<"------------------调用user 的析构函数------------------"<<endl;
        }
    };
    int main()
    {
        memorypool<user>m_pool;
        user*dp1=(user*)m_pool.allocate(1);
        cout<<"dp1= "<<dp1<<endl;
        new(dp1)user(1111);
        cout<<" 对象中的数据值为 "<<dp1->get()<<endl;
        user*dp2=(user*)m_pool.allocate(1);
        cout<<"dp2= "<<dp2<<endl;
        new(dp2)user(2222);
        cout<<"对象中的数据值为 "<<dp2->get()<<endl;
         user*dp3=(user*)m_pool.allocate(1);
        cout<<"dp3= "<<dp3<<endl;
        new(dp3)user(3333);
        cout<<"对象中的数据值为 "<<dp3->get()<<endl;
         user*dp4=(user*)m_pool.allocate(1);
        cout<<"dp4= "<<dp4<<endl;
        new(dp4)user(4444);
        cout<<"对象中的数据值为 "<<dp4->get()<<endl;
         user*dp5=(user*)m_pool.allocate(1);
        cout<<"dp5= "<<dp5<<endl;
        new(dp5)user(5555);
        cout<<"对象中的数据值为 "<<dp5->get()<<endl;
         user*dp6=(user*)m_pool.allocate(1);
        cout<<"dp6= "<<dp6<<endl;
        new(dp6)user(6666);
        cout<<" 对象中的数据值为 "<<dp6->get()<<endl;
    
         user*dp7=(user*)m_pool.allocate(1);
       cout<<"dp7= "<<dp7<<endl;
        new(dp7)user(7777);
        cout<<" 对象中的数据值为 "<<dp7->get()<<endl;
    
        user*dp8=(user*)m_pool.allocate(1);
       cout<<"dp8= "<<dp8<<endl;
        new(dp8)user(8888);
        cout<<" 对象中的数据值为 "<<dp8->get()<<endl;
    
         user*dp9=(user*)m_pool.allocate(1);
        cout<<"dp9= "<<dp9<<endl;
        new(dp9)user(9999);
        cout<<" 对象中的数据值为 "<<dp9->get()<<endl;
    
         user*dp10=(user*)m_pool.allocate(1);
        cout<<"dp10= "<<dp10<<endl;
        new(dp10)user(11111);
        cout<<" 对象中的数据值为 "<<dp10->get()<<endl;
    
         user*dp11=(user*)m_pool.allocate(1);
        cout<<"dp11= "<<dp11<<endl;
        new(dp11)user(22222);
        cout<<" 对象中的数据值为 "<<dp11->get()<<endl;
    
         user*dp12=(user*)m_pool.allocate(1);
        cout<<"dp12= "<<dp12<<endl;
        new(dp12)user(33333);
        cout<<" 对象中的数据值为 "<<dp12->get()<<endl;
    
         user*dp13=(user*)m_pool.allocate(1);
        cout<<"dp13= "<<dp13<<endl;
        new(dp13)user(44444);
        cout<<" 对象中的数据值为 "<<dp13->get()<<endl;
    
         user*dp14=(user*)m_pool.allocate(1);
        cout<<"dp14= "<<dp14<<endl;
        new(dp14)user(55555);
        cout<<" 对象中的数据值为 "<<dp14->get()<<endl;
    
         user*dp15=(user*)m_pool.allocate(1);
        cout<<"dp15= "<<dp15<<endl;
        new(dp15)user(66666);
        cout<<" 对象中的数据值为 "<<dp15->get()<<endl;
        return 0;
    }

    至此 ,内存池的设计以及实现完成。

  • 相关阅读:
    关于UI设计的文章汇总
    Linq 中不爽之处
    难题autoconf、automake、libtool
    静态构造函数线程安全的几个版本[转载]
    Window Live Writer
    Guid、Int、BigInt编号的速度和存储空间的比较
    MVP模式中的P和V关系
    LR 剖析器
    快速软件开发 学习笔记 之七
    快速软件开发 学习笔记 之六
  • 原文地址:https://www.cnblogs.com/guoyu1024/p/9607079.html
Copyright © 2011-2022 走看看