1 引言
我们通常的内存管理方式是申请固定大小的一段内存,并采用链表的方式对其进行管理,这样可能会遇到几个问题:
1、 采用链表方式无法实现小内存的申请;
2、 另一个问题是内存申请边界问题;
3、 无法满足任意大小的内存申请;
4、 无法满足任意数量的内存申请;
我认为一个设计全面的内存池模型应该满足上面的四个条件。
2 内存池结构
图2.1内存池模型结构图
3 底层缓冲区的设计
底层的设计是内存池的关键地方,底层设计得第一步先申请一个内存块,然后对内存块进行初始化。下面采用链表得方式对内存块进行初始化:
#define MAX_BLOCKS 1024 //一个DataBlock类最大容纳对象个数1024个
class DataBlock
{
public:
explicit DataBlock(size_type block_size); //构造函数
~DataBlock(); //析构函数
private:
struct BlockNode
{
BlockNode* next_;
};
typedef BlockNode * NodePtr;
const NodePtr end_node() const{ return (NodePtr)0; }
unsigned char * base_addr_; //内存首地址
};
DataBlock::DataBlock(size_type block_size)
{
base_addr_ = new unsigned char[block_size_ * MAX_BLOCKS];
/*初始化,生成链表*/
NodePtr node = head_node_ = (NodePtr)base_addr_;
head_node_->next_ = end_node();
for (size_type n = 1; n < MAX_BLOCKS; n++) {
node->next_ = (NodePtr)(base_addr_ + n*block_size_);
node = node->next_;
node->next_ = end_node();
}
}
上面的过程就是把已分配的内存进行链表化,把每隔block_size_长度的地方作为链表的节点;当外部需要block_size_内存时我们就可以把剩余链表的节点返回给用户,比如下面内存分配函数的实现方法:
void * DataBlock::allocate(size_type block_size)
{
if (block_size > block_size_)
return (void*)end_node();
NodePtr node = head_node_;
if (head_node_ != end_node() )
head_node_ = head_node_->next_;
return (void*)node;
}
Head_node_为链表的头节点,每次分配返回头结点的地址,并且对block_size_进行判断,以免外部的block_size_非法。地址的释放操作如下:
Void DataBlock::deallocate(void * p, size_type block_size)
{
if (block_size > block_size_)
return;
NodePtr node = reinterpret_cast<NodePtr>(p);
node->next_ = head_node_;
head_node_ = node;
}
把外部需要释放的内存作为链表的头节点插入链表,就完成内存的回收。
《未完待续》......