zoukankan      html  css  js  c++  java
  • 一个简单定长内存池的设计实现

        主要分为 3 个部分,memoryPool 是管理内存池类,block 表示内存块,chunk 表示每个存储小块。它们之间的关系为,memoryPool 中有一个指针指向某一起始 block,block 之前通过 next 指针构成链表结构的连接,每个 block 包含指定数量的 chunk。每次分配内存的时候,分配 chunk 中的数据地址。

    内存池设计文档

    主要数据结构设计:

    Block:

    struct block {
        block * next;//指向下一个block指针
        unsigned int numofChunks;
        unsigned int numofFreeChunks;//剩余free的chunk数量
        unsigned int blockNum;//该block的编号
        char * data;
        queue<int> freepos; //记录可用chunk序号
    };

    MemoryPool:

    class memoryPool {
        unsigned int initNumofChunks; //每个block的chunk数量
        unsigned int chunkSize;//每个chunk的数据大小
        unsigned int steps;//每次扩展的chunk数量
        unsigned int numofBlocks;//当前管理多少个blocks
        block * blocksPtr;//指向起始block
        block * blocksPtrTail;//指向末尾block
        block * firstHasFreeChunksBlock;//指向第一个不为空的block
    };

    Chunk:

    image

    ChunkNum:该 chunk 所在 block 里的编号

    blockAddress: 该 chunk 所对应的 block,主要用于 free 这个 chunk 的时候,能够快速找到所属 block,并进行相应更新

    data:实际供使用的数据起始位置

    关键操作说明:

    内存分配:

    从 firstHasFreeChunksBlock 开始查找第一个有 free 位置的 block,如果找到,则则获取该 block 的 freepos 的队首元素,返回该元素序号对应的 chunk 的数据地址,并将 freepos 的队首元素弹出,其他相关属性更新。如果找不到,则新增 steps 个 chunk,再重复上面的过程。

    内存释放:

    传入待释放的地址指针p,通过对p的地址移动可以找到chunk中的 ChunkNum 和 blockAddress 两个数据,通过 blockAddress 可以找到该 chunk 所属的 block,然后将ChunkNum 添加到该 block 的 freepos 中,其他相应属性更新。

    使用方法:

    memoryPool * mp = new memoryPool (256);   
      char * s = (char *)mp->allocate(); 
      // 一些操作 
      mp->freeMemory(s);     
      delete mp;

    不足:

    没考虑线程安全问题,该实现方案在单线程下可以正常运行。

    程序源代码:

    #include <iostream>
    #include <queue>
    #include <string.h>
    #include <ctime>
    using namespace std;
    
    struct block {
        block * next;
        unsigned int numofChunks;//指向下一个block指针
        unsigned int numofFreeChunks;//剩余free的chunk数量
        unsigned int blockNum;//该block的编号
        char * data;
        //记录可用chunk序号
        queue<int> freepos;
        block(unsigned int _numofChunks ,unsigned int _chunkSize, unsigned int _blockNum){
            numofChunks =  _numofChunks;
            numofFreeChunks = _numofChunks;
            blockNum = _blockNum;
            next = NULL;
            data = new char [numofChunks * (sizeof(unsigned int) + sizeof(void *) + _chunkSize)];
            char * p = data;
            //每个chunk的结构:4byte的chunk序号 + 4byte的所属block地址 + 真正的数据
            for(int i=0;i<numofChunks;i++){
                char * ptr = p + i * (_chunkSize +  sizeof(unsigned int) + sizeof(void *));
                unsigned int * num = (unsigned int *)(ptr);
                *num = i;
                ptr += sizeof(void *);
                int * blockpos = (int *) ptr;
                *blockpos = (int)this;
                freepos.push(i);
            }
        }
        ~block(){
            delete [] data;
        }
    };
    
    
    class memoryPool {
    public :
        memoryPool(unsigned int _chunkSize = 256, unsigned int _initNumofChunks = 4096, unsigned int _steps = 64){
            initNumofChunks = _initNumofChunks;
            chunkSize = _chunkSize;
            steps = _steps;
            numofBlocks = steps;
            //创建内存池时,初始化一定数量的内存空间
            block * p = new block(initNumofChunks, chunkSize, 0);
            blocksPtr = p;
            for(int i=1;i<steps;i++){
                p->next = new block(initNumofChunks, chunkSize, i);
                p = p->next;
                blocksPtrTail = p;
            }
            firstHasFreeChunksBlock = blocksPtr;
        }
        ~memoryPool(){
            block  * p = blocksPtr;
            while(blocksPtr!=NULL){
                p = blocksPtr->next;
                delete blocksPtr;
                blocksPtr = p;
            }
        }
    
        /*
        从firstHasFreeChunksBlock开始查找第一个有free位置的block,
        如果找到,则则获取该block的freepos的对首元素,
        返回该元素序号对应的chunk的数据地址,并将freepos的队首元素弹出,
        其他相关属性更新。如果找不到,则新增steps个chunk,再重复上面的过程。
        */
        void * allocate(){
            block * p = firstHasFreeChunksBlock;
            while(p != NULL && p->numofFreeChunks <= 0) p = p->next;
            if(p == NULL){
                p = blocksPtrTail;
                increaseBlocks();
                p = p->next;
                firstHasFreeChunksBlock = p;
            }
            unsigned int pos =  p->freepos.front();
            void * chunkStart = (void *)(p->data + pos * (chunkSize +  sizeof(unsigned int) + sizeof(void *)));
            void * res = chunkStart + sizeof(unsigned int) + sizeof(void *);
            p->freepos.pop();
            p->numofFreeChunks --;
            return res;
        }
    
        void increaseBlocks(){
            block * p = blocksPtrTail;
            for(int i=0; i<steps; i++){
                p->next = new block(initNumofChunks, chunkSize, numofBlocks);
                numofBlocks++;
                p = p->next;
                blocksPtrTail = p;
            }
        }
        /*
        传入待释放的地址指针_data,
        通过对_data的地址移动可以找到chunk中的ChunkNum和blockAddress两个数据,
        通过blockAddress可以找到该chunk所属的block,
        然后将ChunkNum添加到该block的freepos中,其他相应属性更新。
        */
        void freeMemory(void * _data){
            void * p = _data;
            p -= sizeof(void *);
            int * blockpos = (int *) p;
            block * b = (block *) (*blockpos);
            p -= sizeof(unsigned int);
            int * num = (int *) p;
            b->freepos.push(*num);
            b->numofFreeChunks ++;
            if (b->numofFreeChunks > 0 && b->blockNum < firstHasFreeChunksBlock->blockNum)
                firstHasFreeChunksBlock = b;
        }
    
    private :
        unsigned int initNumofChunks; //每个block的chunk数量
        unsigned int chunkSize;//每个chunk的数据大小
        unsigned int steps;//每次扩展的chunk数量
        unsigned int numofBlocks;//当前管理多少个blocks
        block * blocksPtr;//指向起始block
        block * blocksPtrTail;//指向末尾block
        block * firstHasFreeChunksBlock;//指向第一个不为空的block
    };
    
    //test
    void echoPositionNum(char * p){
        p -= (sizeof(void *) + sizeof(unsigned int));
        int * num = (int *) p;
        cout<<*num<<endl;
    }
    
    //测试
    void test0(){
        memoryPool mp;
        char * s1 = (char *)mp.allocate();
        char * s2 = (char *)mp.allocate();
    
        char str [256];
        char str2 [256];
        char str3 [256];
        for(int i=0; i<255; i++) {
            str[i] = 'a';str2[i] = 'b';str3[i] = 'c';
        }
        str[255] = '\0';
        str2[255] = '\0';
        strcpy(s1,str);
        strcpy(s2,str2);
        str3[255] = '\0';
        echoPositionNum(s1);
    
        cout<<s1<<endl;
        mp.freeMemory(s1);
        echoPositionNum(s2);
        cout<<s2<<endl;
        char * s3 = (char *)mp.allocate();
        strcpy(s3,str3);
    
        echoPositionNum(s3);
        cout<<s3<<endl;
    
    }
    
    void test1(){
        clock_t clock_begin = clock();
        const int N = 50000;
        char * s[N];
        int round = 100;
        while(round>=0){
            round --;
            for(int i=0;i<N;i++){
                s[i] = new char[256];
            }
            for(int i=0;i<N;i++){
                 delete [] s[i];
            }
        }
        clock_t clock_end = clock();
        cout<<"Time cost\t"<<clock_end - clock_begin<<endl;
    }
    
    void test2(){
    
        memoryPool mp(256);
        clock_t clock_begin = clock();
        const int N = 50000;
        char * s[N];
        int round = 100;
        while(round>=0){
            round --;
            for(int i=0;i<N;i++){
                s[i] = (char *)mp.allocate();
            }
            for(int i=0;i<N;i++){
                mp.freeMemory(s[i]);
            }
        }
        clock_t clock_end = clock();
        cout<<"Time cost\t"<<clock_end - clock_begin<<endl;
    
    }
    int main()
    {
        test0();
        test1();
        test2();
        return 0;
    }

    运行结果:

    image

  • 相关阅读:
    茗洋ASP.NET MVC4 IN ACTION 教程目录
    C#实验室<群内活动>2013年5月12日的算法题目记录[胜者:Yamat]
    那天有个小孩跟我说LINQ(四)
    C#实验室同盟测试iframe
    C#实验室同盟测试页
    那天有个小孩跟我说LINQ(五)
    C#实验室<常用软件>Windows Live Writer
    ASP.NET MVC4 IN ACTION学习笔记第六波[Ajax in ASP.NET MVC][1/3]
    那天有个小孩跟我说LINQ(六)
    ASP.NET MVC4 IN ACTION学习笔记第四波
  • 原文地址:https://www.cnblogs.com/coser/p/2964679.html
Copyright © 2011-2022 走看看