一级空间配置器:https://blog.csdn.net/qq_37964547/article/details/80474316
一、二级空间配置器
在前面文章中我们介绍了一级空间配置器的概念和实现,一级空间配置器的实现相对比较简单,直接封装了malloc()和free()函数,同时增加了处理机制et_malloc_handler() 。 一级空间配置器主要处理大于128字节的大块内存分配问题,当字节数小于128字节,我们就需要用到二级空间配置器进行空间申请;
STL默认是使用二级空间配置器。
1、二级空间配置器的配置方法
(1)如果申请的区块够大,超过128bytes时,就移交给一级配置器处理
(2)当区块小于128时,则以内存池(memory pool)管理,此法又称为次层配置 : 每次配置一大块内存,并维护对应的自由链表(free list)。下次如在需要相同大小的内存需求时,就直接free lists中拔出。如果客户释放了小额区块时,就由配置器回收到free lists中。为了方便管理,SGI第二级配置器会主动将任何小额区块的内存扩充至8的倍数(比如申请20bytes,就会调整至24bytes),并维护8,16,24,32,40,48,56,64,72,80,88,94,104,112,128bytes的对应大小的自由链表。
2、空间配置器结构图
3、具体实现过程
为了维护链表,需要额外的指针,为了避免造成另外一种额外的负担,这里采用了一种技术:用union表示链表节点结构:
union OBJ
{
OBJ* _freeListLink; //指向下一个节点的指针
char clientData[1]; //* The client sees this. */
};
4、void *Allocate(size_t n)函数解析
具体实现思想如下:
内存池有空间:
(1)内存池剩余空间完全满足20个区块的需求量,则直接取出对应大小的空间。
(2)内存池剩余空间不能完全满足20个区块的需求量,但是足够供应一个及一个以上的区块,则取出能够满足条件的区块个数的空间。
(3)内存池剩余空间不能满足一个区块的大小,则首先判断内存池中是否有残余零头内存空间,如果有则进行回收,将其编入free list;然后向heap申请空间,补充内存池。
heap申请空间:
(1)heap空间满足,空间分配成功。
(2)heap空间不足,malloc()调用失败。则搜寻适当的free_ list(适当的是指:尚有未用区块,并且区块足够大),调整以进行释放,将其编入内存池。然后递归调用chunk_alloc函数从内存池取空间供free list。
(3)搜寻free list释放空间也未能解决问题,这时候调用第一级配置器,利用out-of-memory机制尝试解决内存不足问题。如果可以就成功,否则排除bad_alloc异常。
Allocate函数代码:
static void *Allocate(size_t n)
{
if (n > _MAX_BYTES)
return MallocAllocTemplate<0>::Allocate(n);
__TRACE_DEBUG("二级:%d\n", n);
size_t index = FREELIST_INDEX(n);//找到对应下标位置
if (NULL == _freeList[index])
{
__TRACE_DEBUG("二级:%d桶中没有可用空间,需要内存池补充\n", index);
return ReFill(ROUND_UP(n)); //为free_list填充空间