STL 二级空间配置器

当程序需要在堆上申请空间时,我们常用的做法是直接malloc / new一块新的内存空间,这块被申请的空间需要我们手动释放,频繁的申请释放必然会导致系统产生大量内存碎片,尤其是小额区块的申请,内存碎片和额外负担很大的损害了我们的内存空间。
在STL中对于内存的申请,有着更高明的手法——allocator(空间配置器)。
一级空间配置器很简单,只是简单的将malloc进行封装,加入了异常处理机制,申请失败会调用 _oom_malloc_handle,期望通过释放其他不用的空间来重新分配,这样的做法对于内存的管理实际上并没有什么优化。
关键在于二级空间配置器——__default_alloc_template 。

SGI二级配置的做法是,如果申请的区块够大,超过128bytes时,就移交给一级配置器处理,而当区块小于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的对应大小的自由链表。
自由链表需要指针进行维护,为了节省开销。我们采用公用体来定义自由链表,如下:

union obj
{
    union obj * free_list_link;
    char client_data[1];
};

我们先来看看二级空间配置器的具体操作流程:
这里写图片描述
1 当用户申请内存时,大于128bytes交于第一级配置器直接在内存中malloc空间。小于128交于第二级空间配置器。

2 第二级配置器先根据申请大小,比如30,上升至8的倍数32,并在16条链表中锁定第3条链表,判断链表中是否有32位内存块可供分配(我们第一次申请,没有),那么接着在查看内存池是否还有空间(同样,我们第一次申请,并没有内存池)。

3 那配置器开始向系统申请 32 * 20 * 2 这么大小的内存块,其中20个作为自由链表挂载到第3条链表下(第3条链表对应32位大小的内存),并把第一块内存分配给申请的用户(第3条链现在挂载了19块32位的内存),而剩下的32 * 20大小的空间作为内存池,用head指针指向内存池的头,tail指针指向内存池的尾,记录下内存池。

4 当下一次用户再次申请空间时,比如28bytes,配置器将其上升至32bytes,锁定到第三条链表,查看链表不为空,记录共用体指针,用户写下数据data,记录的指针++,指向下一个32位的内存块。分配成功!
当然,如果申请大小不是24~32位之内的,那么锁定到其他的链表中(比如申请int型,锁定到第0条链表),发现没有对应的内存块,接着查看内存池(32 * 20大小),内存池不为空,判断内存池大小是否大于 8 * 20 ,发现大于,那么就将8*20的大小分配出去,将20个8bytes内存块挂载到第0号自由链表下面,并分配出去一个8bytes给用户,现在剩下19个8bytes大小在0号下面。同时,内存池的head指针指向8*20后,所以内存大小还剩下480bytes。

6 再次申请空间,大小在24~32之间,适配器就将内存池剩下的32bytes分配给用户,内存池为空。当大小大于32位时呢?适配器将先把32bytes挂载到对应链表的内存块下面,也就是2号下面,头插法插入内存块中。然后在向系统malloc空间,比如你需要40bytes,再次malloc 40 * 20 * 2大小的空间,19个挂载到4号链表下面,而剩下40 * 20成为新的内存池大小。

7 当上一个步骤malloc失败了怎么办?也就是说系统现在没有可用的内存供你malloc了,那么会这么做:

for(i = size; i <= _MAX_BYTES; i += _ALIGN)

就是从4号链表开始查找,链表下的内存块有没有空闲的,4号没有,查找5号48bytes对应的链表,一直查找到7号链表,还有19个64bytes的内存块,拔出一个给用户(虽然用户需要40bytes,我们现在给64bytes有浪费&

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值