第一级空间配置器

  第一级配置以malloc(), free(), realloc()等c函数执行实际的内存配置,释放、重配置操作,并实现出类似c++ new handler的机制。它不能直接使用c++ new handler机制,因为它并非使用::operator new来配置内存。

  所谓的c++ new handler机制,就是你可以要求系统在内存配置需求无法被满足时,调用一个你所指定的函数。换句话说,一旦::operator new无法完成任务,在丢出std::bad_alloc异常状态之前,会调用一个由客户端指定的处理例程。该处理例程被称为c++ new handler。new handler解决内存不足的做法有特定的模式。

  //oom指:out of memory

  SGI以malloc而不是::operator new来配置内存,因此SGI不能直接使用C++的set_new_handler(),必须仿真一个类似的set_new_handler()。SGI低一级配置器的allocate()和realloc() 都是在调用malloc()和realloc()不成功之后,改调用oom_malloc()和oom_realloc()。后两者都有内循环,不断调用“内存不足处理例程”,期望在某次调用之后获得足够的内存圆满完成任务。但是如果“内存不足处理例程”并未被客户端设定,oom_malloc()和oom_realloc()便会调用_THROW_BAD_ALLOC,丢出bad_alloc异常信息,或利用二线exit(1)直接终止程序。

第二级空间配置器

  第二级配置器多了一些机制,避免太多小额区块造成内存的碎片。小额区块带来的其实不仅仅是内存碎片,配置时的额外负担(overhead系统开销(计算机网络)overhead,在计算机网络帧结构中,除了有用数据以外,还有很多控制信息,这些控制信息用来保证通信的完成。这些控制信息被称作系统开销。)也是一个大问题。额外负担永远无法避免,毕竟系统要靠这多出来的空间来管理内存。

  SGI第二级配置器的做法是,如果区块够大,超过128bytes时,就移交给第一级配置器处理。当区块小于128bytes时,则以内存池(memory pool)的方式管理,此法又称之为层次配置(sub_allocation):每次配置一大块内存,并维护对应的自由链表(free list)。下次若再有相同大小的内存需求,就直接从free-lists中拨出。如果客户端释放了小额区块,也负责回收。为了方便管理,SGI第二级配置器会主动将任何小区块的内存需求量上调至8的倍数(如需求为30bytes,自动调整为32bytes)。并维护16(128/8=16)个free-lists,各自管理的大小为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128的小额区块。

  free-lists的结构如下:

union obj{

union obj * free_list_link;

char client_data[1];   /*the client sees this.*/

    }

  大家可能会想为了维护链表,每个节点都需要额外的指针指向下一个节点,这不又造成了另一种额外负担么?但是请注意,上述obj所用的是union,所以从其第一个字段来看,obj可以被当做一个指向形式相同的另一个obj的指针;从第二个字段来看,可以把它看做指向实际区块的指针。

内存分配策略:

叙述之前做一下约定:

req_size ,表示用户请求的内存大小。

_round_up(size_t size),表示对用户请求的内存大小,向上调整为8的倍数。

例如:req_size = 14 , 那么_round_up(req_size ) 的返回值是16。

_pool_watermark(size_t size),表示用户请求的内存在head_list中的下标。

例如:req_size = 14 , 那么_pool_watermark(req_size ) 的返回值是1。

具体策略:
1)如果用户申请超过128字节的内存,则直接调用第一级简单空间配置器;否则,执行2)。

2)小于128bytes就检测对应的free-lists,如果free list之内有可用的区块,就直接返回给用户。如果没有可用区块,就将区块大小上调至8的倍数边界,然后调用refill(),准备为free list重新填充空间。

内存池取空间操作

从内存池中取空间给free
list,是chunk_alloc()的工作。其工作流程如下:

chunk_alloc()中以end_free
– start_free 来判断内存池是的剩余内存。

1, 
如果内存充足,则直接调出20个区块返回给对应的free list。

2, 
如果内存不足,但是end_free – start-free的值仍然大于size,即可以提供一个以上的区块,就提供这不足20的区块出去,这时候pass by reference 的nobjs参数将被修改为实际供应的区块个数。

3, 
如果剩余内存不足提供一个区块,则调用malloc从heap中分配内存给内存池。

  a) 如果heap足够,则分配20*2+n(n为附加量,随着分配次数的增加而增加)的内存块给内存池,其中第一个给用户,19个给free list维护,剩余的20+n个给内存池维护。

  b) 如果heap也没了,malloc失败,chunk alloc()就搜寻整儿free list看是否有“尚未利用的区块,且区块足够大”,如果有则分配给用户。

  c) 如果没搜寻到,则调用第一级空间配置器。第一级空间配置器也采用的是malloc,但是第一级空间配置器有out of memory处理机制(类似new handler处理机制),或许有机会释放出内存,如果可以就成功,否则抛出bad_alloc异常。

内存释放策略

如果释放的内存超过128字节,则调用“简单空间配置器”的内存释放函数。否则,找出对应的free list,将区块收回。

[stl] SGI STL的空间配置器的更多相关文章

  1. STL源码剖析 — 空间配置器(allocator)

    前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...

  2. STL源码剖析(空间配置器)

    前言 在STL中,容器的定义中都带一个模板参数,如vector template <class T, class Alloc = alloc> class vector {...} 其中第 ...

  3. STL学习笔记:空间配置器allocator

    allocator必要接口: allocator::value_type allocator::pointer allocator::const_pointer allocator::referenc ...

  4. STL源码剖析——空间配置器Allocator#1 构造与析构

    以STL的运用角度而言,空间配置器是最不需要介绍的东西,因为它扮演的是幕后的角色,隐藏在一切容器的背后默默工作.但以STL的实现角度而言,最应该首先介绍的就是空间配置器,因为这是这是容器展开一切运作的 ...

  5. STL源码剖析——空间配置器Allocator#2 一/二级空间配置器

    上节学习了内存配置后的对象构造行为和内存释放前的对象析构行为,在这一节来学习内存的配置与释放. C++的内存配置基本操作是::operator new(),而释放基本操作是::operator del ...

  6. STL源码剖析——空间配置器Allocator#3 自由链表与内存池

    上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...

  7. STL源码分析读书笔记--第二章--空间配置器(allocator)

    声明:侯捷先生的STL源码剖析第二章个人感觉讲得蛮乱的,而且跟第三章有关,建议看完第三章再看第二章,网上有人上传了一篇读书笔记,觉得这个读书笔记的内容和编排还不错,我的这篇总结基本就延续了该读书笔记的 ...

  8. STL——空间配置器(构造和析构基本工具)

    以STL的运用角度而言,空间配置器是最不需要介绍的东西,它总是隐藏在一切组件(更具体地说是指容器,container)的背后,默默工作,默默付出.但若以STL的实现角度而言,第一个需要介绍的就是空间配 ...

  9. STL 之 空间配置器(allocator)

    一.SGI 标准的空间配置器,std::allocator SGI也定义了一个符合部分标准,名为allocator的配置器,但是它自己不使用,也不建议我们使用,主要原因是效率不佳. 它只是把C++的操 ...

  10. STL——空间配置器(SGI-STL)

    一. 空间配置器标准接口 参见<STL源码剖析>第二章-2.1.<memory>文件. 二.具备次配置力的SGI空间配置器 1. SGI STL的配置器与众不同,也与标准规范不 ...

随机推荐

  1. java攻城狮之路(Android篇)--与服务器交互

    一.图片查看器和网页源码查看器 在输入地址的是不能输入127.0.0.1 或者是 localhost.ScrollView :可以看成一个滚轴 可以去包裹很多的控件在里面 练习1(图片查看器): pa ...

  2. ruby -- 基础学习(五)empty、nil、blank三者之间的区别

    这三个方法在ROR中经常用到,都是用来判断是否为空的. 区别是: ruby的方法:.nil?..empty? rails的方法 :.blank? 用法的区别: .nil?    :   判断对象是否存 ...

  3. NopCommerce插件学习

    在园子里看到这篇文章:http://www.cnblogs.com/haoxinyue/archive/2013/06/06/3105541.html写的非常好,我也是在此文章的基础上来一步步的学习N ...

  4. 将STM32的标准库编译成lib

    转载自:http://www.cnblogs.com/zyqgold/p/3189719.html 以前一直使用STM32的标准库,需要一步步地将代码加进去,将编译选项设置好,然后再编译整个工程. 这 ...

  5. c#关于委托和事件(二)(介绍的很详细)

    using System;using System.Collections.Generic;using System.Text; namespace Delegate {    // 热水器    p ...

  6. Python装饰器由浅入深

    装饰器的功能在很多语言中都有,名字也不尽相同,其实它体现的是一种设计模式,强调的是开放封闭原则,更多的用于后期功能升级而不是编写新的代码.装饰器不光能装饰函数,也能装饰其他的对象,比如类,但通常,我们 ...

  7. thread_AtomicBoolean

    Boolean值的变化的时候不允许在之间插入,保持操作的原子性 它提供了原子性操作,其中exists.compareAndSet(false, true)这个操作把比较和赋值操作组成了一个原子操作,中 ...

  8. LeetCode - 41. First Missing Positive

    41. First Missing Positive Problem's Link ---------------------------------------------------------- ...

  9. VC包含目录、附加依赖项、库目录及具体设置

    包含目录:#include <headerfile.h>中headerfile.h的搜索目录.如果有XXX.h找不到,设置这个目录可以解决. 附加依赖项:C++的库会把函数.类的声明放在* ...

  10. IOS 之 PJSIP 笔记(一) 编译多平台支持的静态库

    好久没有写博客了,这也算是我步入新工作后的第一篇技术博文吧.在进入新公司前,早就有了技术层进入下一个迭代的准备,但很多事情是意想不到的,就像我以 C# 程序员的身份面试入职的,而今却是一个全职的 IO ...