内存池的弟弟---对象池

内存池的弟弟—对象池

关于什么是内存池,内存池有什么优势,什么是对象池我已经在我的GitHub上写在了Readme.md文件里了,GitHub链接

这篇博客主要讲一下一个简单的对象池实现过程。

对象池的结构:

  • 首先我确定了一个类ObjectPool来实现一个链表,这个链表上的每一个结点都挂着一个内存块。
  • 然后在ObjectPool类里,有一个内置结构体,用来申请内存块。
  • 先申请一块默认大小的内存块,当这个内存块分配完了之后,再申请另一块内存,用链表组织起来,并且内存块的大小是一个二倍增长的。
  • 最后这个结构的难点在于如何处理用户还回来的内存。一般的处理方法是组织一个_free_list空闲链表。每当用户还回来一块内存(一块内存是一个对象的大小),就把这块内存头插到这个链表里面。
  • 在分配内存的时候,优先从空闲链表里取内存,只需要将第一个结点返回即可。如果空闲链表为空,那么再看内存块是否还有内存可供分配,如果没有再次申请一个2倍大小的内存块,尾插到内存块链表中。
  • 注意:由于内存块分配出去后,用户再还回来是头插到空闲链表中,所以我们将不对内存块链表中的每一个结点进行记录,只需要记录内存块链表的最后一个结点即可。当然第一个结点也要记录,到最后销毁的时候需要从第一个结点开始释放。

代码:

#pragma once
#include <iostream>

template <class T>
class ObjectPool
{
private:
    //管理内存块
    struct Block
    {
        //按字节数去管理,比较好控制
        //内存块管理
        char* _start = nullptr;
        
        size_t _byte_size = 0; //表示块有多少个字节
        size_t _byte_left = 0; //表示块剩余多少个字节
        Block* _next = nullptr; //链接下一个块


        Block(size_t byte_size)
        {
            _start = (char*)malloc(byte_size);
            _byte_size = byte_size;
            _byte_left = byte_size;
            _next = nullptr;
        }

        ~Block()
        {
            free(_start);
            _byte_left = 0;
            _byte_size = 0;
            _next = nullptr;
        }
    };

public:
    //init_num 表示第一次申请多少个对象
    ObjectPool(size_t init_num = 32)
    {
        //申请出来第一个块
        _head = _tail = new Block(init_num * _obj_size);
    }

    ~ObjectPool()
    {
        Destory();
    }

    T*& ObjNext(T* memory)
    {
        return *(T**)memory;
    }

    //只提供每次调用提供一个对象
    T* New()
    {
        T* obj = nullptr;
        //如果空闲链表有结点,优先在空闲链表里面取内存
        if (_free_list != nullptr)
        {
            obj = _free_list;
            _free_list = ObjNext(_free_list);
        }
        else//表示空闲链表没有结点,这个时候要在Block内存块里切内存
        {
            //先检查Block里面还还没有内存
            //如果当前的Block已经没有空间可以分配
            if (_tail->_byte_left == 0)
            {
                Block* newBlock = new Block(_tail->_byte_size * 2);
                _tail->_next = newBlock;
                _tail = newBlock;
            }

            //走到这里表示一定有内存
            obj = (T*)_tail->_start + (_tail->_byte_size - _tail->_byte_left);
            //将剩余的字节数更新
            _tail->_byte_left -= _obj_size;

        }
        new(obj) T();
        return obj;
    }

    void Delete(T* memory)
    {
        memory->~T();
        if (_free_list == nullptr)
        {
            _free_list = memory;

            //(*(T**)memory) = nullptr;
            ObjNext(memory) = nullptr;
        }
        else
        {
            //(*(T**)memory) = _free_list;
            ObjNext(memory) = _free_list;
            _free_list = memory;
        }
    }

    void Destory()
    {
        while (_head != nullptr)
        {
            delete _head;
            _head = _head->_next;
        }

        _head = nullptr;
        _tail = nullptr;
    }

private:
    static size_t ObjSize()
    {
        return sizeof(T) > sizeof(T*) ? sizeof(T) : sizeof(T*);
    }

private:
    //空闲链表管理指针
    T* _free_list = nullptr;

    //块管理
    Block* _head = nullptr;
    Block* _tail = nullptr;

    //对象大小,因为可能对象的字节数小于指针
    static size_t _obj_size;
};

template <class T>
size_t ObjectPool<T>::_obj_size = ObjectPool<T>::ObjSize();

如何联系我?

如果你遇到任何问题,可以给我发邮件:18192648006@163.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值