基于一个简单定长内存池的实现方法详解

2016-02-19 09:39 19 1 收藏

今天天气好晴朗处处好风光,好天气好开始,图老师又来和大家分享啦。下面给大家推荐基于一个简单定长内存池的实现方法详解,希望大家看完后也有个好心情,快快行动吧!

【 tulaoshi.com - 编程语言 】

    主要分为 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;
    queueint 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:

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序号
    queueint 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;inumofChunks;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;isteps;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; isteps; 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*numendl;
}

//测试
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; i255; i++) {
        str[i] = 'a';str2[i] = 'b';str3[i] = 'c';
    }
    str[255] = '';
    str2[255] = '';
    strcpy(s1,str);
    strcpy(s2,str2);
    str3[255] = '';
    echoPositionNum(s1);

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

    couts1endl;
    mp.freeMemory(s1);
    echoPositionNum(s2);
    couts2endl;
    char * s3 = (char *)mp.allocate();
    strcpy(s3,str3);

    echoPositionNum(s3);
    couts3endl;

}

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;iN;i++){
            s[i] = new char[256];
        }
        for(int i=0;iN;i++){
             delete [] s[i];
        }
    }
    clock_t clock_end = clock();
    cout"Time costt"clock_end - clock_beginendl;
}

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;iN;i++){
            s[i] = (char *)mp.allocate();
        }
        for(int i=0;iN;i++){
            mp.freeMemory(s[i]);
        }
    }
    clock_t clock_end = clock();
    cout"Time costt"clock_end - clock_beginendl;

}
int main()
{
    test0();
    test1();
    test2();
    return 0;
}

运行结果:

image

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

来源:http://www.tulaoshi.com/n/20160219/1591621.html

延伸阅读
标签: Web开发
先去官网下载jQuery Timers插件 ,然后引用到html中。这里是1.2 version 代码如下: script src="../Javascripts/Plugins/jquery.timers-1.2.js" type="text/javascript"/script 然后是HTML,我们可以放一个hidden 的server control存值用,当然这个随你了。 代码如下: asp:HiddenField runat="server" / h1 jQuery Timers Te...
一个简单的登录对话框的实现 作者:不会游泳的鱼 下载源代码 要求用户正确输入用户名和密码,然后才能进入系统。刚好前几天有个人问俺如何在程序启动时先启动登录对话框的问题,俺就给他写了个示例程序,今天拿出来给大伙共享,有什么不正确的地方请大家多多指教。 一、在 LoginTe...
Private Function EncryptString(strString) Dim CharHexSet, intStringLen, strTemp, strRAW, i, intKey, intOffSet Randomize Timer intKey = Round((RND * 1000000) + 1000000) '##### Key Bitsize intOffSet = Round((RND * 1000000) + 1000000) '##### KeyOffSet Bitsize If IsNull(strString) = False Then strRAW = strString intS...
标签: Web开发
script function Menu_Init(obj){    var tds = obj.getElementsByTagName("td");     for (var i = 0; i  tds.length; i++)      {    if (tds[i].className == "MenuOptions")...
有诸多缺点,比如不是时间触发而是靠线程挂起 package com.zhou.clock; import java.awt.*; import java.awt.geom.*; import javax.swing.*; import java.lang.Math; import java.util.Date; public class Clock extends JFrame { ClockPane cp; public Clock (){ super("clock"); setDefaultCloseOperation(EXIT_ON_CLOSE...

经验教程

985

收藏

66
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部