简单的内存池实现

  内存池是用来改善new/delete内存管理机制可能造成的运行效率低下问题的一种技术
  经典的内存池技术,是用一种用于分配大量大小相同的小对象技术,加快内存分配或者释放的过程。
  在看书的过程中,我对简单的实现一个内存池的实现理解是:
    1、让我们在堆上面申请到的内存是连续的。
    2、我们放在内存池中的某个对象,当我们delete它后,我们要再次申请内存的时候,就在刚刚delete的那个位置重新申请,而不是在内存的某个位置申请。
    3、使用多大内存就申请多大的内存存放在内存池。
  根据以上条件来实现,则可以通过一个数组链表来实现,达到上面的第一个条件;第二个条件,我们通过内存块指针与内存节点指针的操作来实现;第三个条件,通过模板来实现。
  (代码与书上的代码相差不大,差别就在于链表指向的顺序,与添加了结构体的构造函数)

代码:

//my_mempool.h
//模板参数为对象的size,与数目
template<int Objectsize,int Objectnumsize=20>
class mempool {
private:
    //Freenode是自由节点,指未被使用的内存节点
    struct Freenode {
        Freenode *next;
        char mes[Objectsize];
        Freenode() :next(nullptr) {}
    };
    //Mmemnode是内存块节点,默认存放20个对象
    struct Memnode {
        Memnode *next;
        Freenode pfree[Objectnumsize];
        Memnode() :next(nullptr) {}
    };
    Memnode *Memheader; //指向内存块第一个节点
    Freenode *Freeheadr;//指向自由内存的头节点
    const int Memblocksize;//内存块大小
    const int Nodesize;//申请的节点大小
public:
    //每个节点除了我们对象本身的大小,还要加上每个节点中的指针大小
    mempool() :Nodesize(Objectsize + sizeof(Freenode*)), Memblocksize(sizeof(Memnode*) + Objectnumsize*(Objectsize + sizeof(Freenode*)))
    {
        Memheader = nullptr;
        Freeheadr = nullptr;
    }
    ~mempool()
    {
        Memnode *ptr;
        while (Memheader)
        {
            ptr = Memheader->next;
            delete Memheader;
            Memheader = ptr;
        }
    }
    //测试每个节点大小是否与初始化Nodesize相同
    void printObjectSize()
    {
        cout << sizeof(Memheader->pfree)/Objectnumsize << endl;
    }
    void* malloc();
    void free(void* ptr);
};

  malloc申请内存的过程是,判freehead也就是内存块中是否还有自由节点,若没有则申请一个内存块如下代码中的memblock,然后初始化memblock的自由节点链表与freeheadr,并把memblock加入内存块链表管理。然后返回指向Freeheadr的指针,也就意味着我们占用了这块内存节点,然后freeheadr指向下一个节点。



template<int Objectsize, int Objectnumsize>
void * mempool<Objectsize, Objectnumsize>::malloc()
{
    if (Freeheadr == nullptr)
    {
        Memnode *memblock = new Memnode;
        for (int i = 1; i < Objectnumsize; i++)
            memblock->pfree[i-1].next = &memblock->pfree[i];
        Freeheadr = &memblock->pfree[0];
        memblock->next = Memheader;
        Memheader = memblock;
    }
    void *temp = Freeheadr;
    Freeheadr = Freeheadr->next;
    return temp;
}

  free的过程就是把原来占用节点重新加入放回自由节点中,将要free的指针设置为自由节点头指针,而原先的freeheadr则为该free的指针的next,在下一次malloc的时候直接返回该指针则达到了申请的内存地址为上一次销毁的内存的地址,例如,p1->p2->freeheadr,我们free(p1)后,就成了p2->原来的freeheadr,p1->原来的freeheadr,而当前的freeheadr=p1,在下次malloc的时候,就返回p1的地址,然后malloc的时候freeheadr=freeheadr->next,也就是p1与p2指向的地方即原先的freeheadr处。


template<int Objectsize, int Objectnumsize>
void mempool<Objectsize, Objectnumsize>::free(void *ptr)
{
    Freenode *currfreeheadr = (Freenode*)ptr;
    currfreeheadr->next=Freeheadr;
    Freeheadr = currfreeheadr;
}

———————————————–main.cpp————————————————–


//main.cpp
class B {
private:
    static int m_count;
    int num[5];
public:
    B() {
        m_count++;
        for (int i = 0; i < 5; i++)
            num[i] = m_count + i;
    }
    void show()
    {
        cout << this << " : ";
        for (int i = 0; i < 5; i++)
            cout << num[i] << " ";
        cout << endl;
    }
    void* operator new(size_t size);
    void operator delete(void* p);
};

//重载new
void * B::operator new(size_t size)
{
    return thepool::mp.malloc();
}
//重载delete
void  B::operator delete(void* p)
{
    return thepool::mp.free(p);
}
class thepool {
public:
    static mempool<sizeof(B), 2>mp; //存储两个B类型对象
    friend class B;
};

int B::m_count = 0;
mempool<sizeof(B), 2> thepool::mp;

int main()
{   
    cout << "sizeof(B) : " << sizeof(B) << endl;
    B *p1 = new B;
    p1->show();
    B *p2 = new B;
    p2->show();
    cout << "(int)p2 - (int)p1 : " <<(int)p2 - (int)p1 << endl;
    delete p1;
    p1 = NULL;
    p1 = new B;
    p1->show();
    B *p3 = new B;
    cout << "(int)p3 - (int)p2 : " << (int)p3 - (int)p2 << endl;
    p3->show();
    B *p4 = new B;
    p4->show();
    cout << "(int)p2 - (int)p1 : " << (int)p4 - (int)p3 << endl;
    delete p4;
    delete p3;
    delete p2;
    delete p1;
    return 0;
}

结果:
这里写图片描述
  从结果我们可以看到,B的类型大小为20,加上指针则为24,我们申请的内存池是一个内存块存储两个对象,所以p1与p2相差的24,由于只存放两个,所以申请p3的时候又申请了一个内存块,所以p3与p2之间的距离差很大。

-----------------------------------------------在写代码的时候碰上的问题-----------------------------------------------

  由于C++基础不扎实,不清楚可以使用模板参数作为数组大小(动态解析机制),我看到用模板里面的参数作为数组的大小的时候,我感觉编译不能通过,一般数组大小都是使用常量表达式,而C++模板可以推导出值,相当于参数的值可以推导出来,相当于这些值是常量表达式。。不知道是不是这么理解。。
  然后因为用模板参数作为数组大小,在写的时候,下面代码在VS2015中,memblock显示没有调用的成员,但是按逻辑写下去是可以运行的,可能这与动态解析有关。

template<int Objectsize, int Objectnumsize>
void * mempool<Objectsize, Objectnumsize>::malloc()
{
    if (Freeheadr == nullptr)
    {
        Memnode *memblock = new Memnode;
        for (int i = 1; i < Objectnumsize; i++)
            memblock->pfree[i-1].next = &memblock->pfree[i];
        Freeheadr = &memblock->pfree[0];
        memblock->next = Memheader;
        Memheader = memblock;
    }
    void *temp = Freeheadr;
    Freeheadr = Freeheadr->next;
    return temp;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存池是一种常见的内存管理技术,它可以在程序启动时预先分配一定数量的内存空间,并将其划分为多个固定大小的块,然后在程序运行过程中动态地将这些块分配给需要使用内存的对象,从而减少内存碎片和内存分配的时间开销。下面是一个简单内存池实现示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define BLOCK_SIZE 1024 #define BLOCK_NUM 10 typedef struct _memory_block { void *start; void *end; struct _memory_block *next; } memory_block; typedef struct _memory_pool { size_t block_size; memory_block *free_list; memory_block *used_list; } memory_pool; memory_pool *memory_pool_create(size_t block_size) { memory_pool *pool = (memory_pool *) malloc(sizeof(memory_pool)); pool->block_size = block_size; pool->free_list = NULL; pool->used_list = NULL; for (int i = 0; i < BLOCK_NUM; i++) { memory_block *block = (memory_block *) malloc(sizeof(memory_block)); block->start = malloc(block_size); block->end = (char *) block->start + block_size; block->next = pool->free_list; pool->free_list = block; } return pool; } void *memory_pool_alloc(memory_pool *pool, size_t size) { memory_block *block = pool->free_list; while (block) { if ((char *) block->end - (char *) block->start >= size) { void *ptr = block->start; block->start = (char *) block->start + size; if (block->start == block->end) { pool->free_list = block->next; block->next = pool->used_list; pool->used_list = block; } return ptr; } block = block->next; } return NULL; } void memory_pool_free(memory_pool *pool) { memory_block *block = pool->used_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } block = pool->free_list; while (block) { memory_block *next = block->next; free(block->start); free(block); block = next; } free(pool); } int main() { memory_pool *pool = memory_pool_create(BLOCK_SIZE); char *str1 = (char *) memory_pool_alloc(pool, 10); char *str2 = (char *) memory_pool_alloc(pool, 20); char *str3 = (char *) memory_pool_alloc(pool, 30); strcpy(str1, "hello"); strcpy(str2, "world"); strcpy(str3, "memory pool"); printf("%s %s %s\n", str1, str2, str3); memory_pool_free(pool); return 0; } ``` 该示例中,首先定义了两个结构体:memory_block表示内存块,包括起始地址、结束地址和下一个内存块的指针;memory_pool表示内存池,包括块大小、空闲链表和已用链表。 然后,定义了三个函数:memory_pool_create用于创建内存池,先分配一定数量的内存块,并将其加入空闲链表;memory_pool_alloc用于从内存池中分配一块指定大小的内存空间,遍历空闲链表,找到第一个大小足够的内存块,并将其划分为新的内存空间;memory_pool_free用于释放内存池中的所有内存块,将已用链表和空闲链表中的内存块全部释放。 最后,在main函数中创建一个内存池,并使用memory_pool_alloc从内存池中分配三个字符串空间,将其赋值并打印出来,最后使用memory_pool_free释放内存池中的所有内存块。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值