内存池的弟弟—对象池
关于什么是内存池,内存池有什么优势,什么是对象池我已经在我的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