new内存释放动作是::operator delete.这两个全域函数相当于 c 的 malloc和 free,SGI 正是以 malloc和 free完成内存的分配与释放。
考虑小型区块可能造成的内存碎片问题,SGI 设计了双层级配置器,低一级分配器直接使用 malloc和 free 第二级分配器则视情况采用不同策略:当分配区块超过 128bytes,则视之“足够大” ,便使用低一级分配器;当分配区块小于 128bytes,则视之“过小” ,便采用复杂的 mempool 方式。
究竟使用哪种分配器,取决于__USE_MALLOC 是否被定义: ifdef __USE_MALLOC ... typedef __malloc_alloc_templatelt0gt malloc_alloc typedef malloc_alloc alloc //令 alloc 为第一级配置器 else ... //令 alloc 为第二级配置器 typedef __default_alloc_templatelt__NODE_ALLOCATOR_THREADS 0gt alloc endif / __USE_MALLOC / 其中,__malloc_alloc_template 就是第一级分配器,__default_alloc_template 就是第二级分配器。
下面的小节中,我想以自底向上的顺序介绍 STL 的 allocator,首先讨论 STL 内建的两种分配器,然后介绍 STL 如何封装这两种分配器对外提供统一的接口,最后用一个 vector的例子看看容器如何使用这个 allocator。
2.2.5 第一级分配器__malloc_alloc_template 该分配器是对 malloc、alloc、free 的封装,并作出类似 c new-handler 的机制(所谓new-handler 机制是指,你可以要求系统在内存分配无法被满足时,唤起一个你所指定的函数,也就是说在::operator::new 无法完成任务,在丢出 std::bad_alloc 异常之前,会先调用用户指定的处理例程,即 new-handler) ,这里作出类似 c new-handler 机制,而不能直接用c new-handler 机制,是因为他不是使用::operator new 来分配内存: if 0 includeltnewgt define __THROW_BAD_ALLOC throw bad_alloc elif defined__THROW_BAD_ALLOC include ltiostream.hgt define __THROW_BAD_ALLOC cerrltltquotout of memoryquotltltendlexit1 endif//注意,无「template 型别参数」 。
至于「非型别参数」inst,完全没派上用场。
template ltint instgtclass __malloc_alloc_template private://以下都是函数指针,所代表的函式将用来处理内存不足的情况。
// oom : out of memory.static void oom_mallocsize_tstatic void oom_reallocvoid size_tstatic void __malloc_alloc_oom_handlerpublic:static void allocatesize_t n void result mallocn//第一级配置器直接使用 malloc // 以下,无法满足需求时,改用 oom_malloc if 0 result result oom_mallocn return resultstatic void deallocatevoid p size_t / n / freep //第一级配置器直接使用 freestatic void reallocatevoid p size_t / old_sz / size_t new_sz void result reallocp new_sz//第一级配置器直接使用 realloc // 以下,无法满足需求时,改用 oom_realloc if 0 result result oom_reallocp new_sz return result//以下模拟 C的 set_new_handler. 换句话说,你可以透过它,//指定你自己的 out-of-memory handlerstatic void set_malloc_handlervoid f//蓝色部分作为参数,最后一个和 void //一起组成 void表示返回值是一个函数指针 void old __malloc_alloc_oom_handler __malloc_alloc_oom_handler f returnold // malloc_alloc out-of-memory handling //初值为 0。
有待用户设定。
__malloc_alloc_oom_handler 是一个函数指针 template ltint instgt void __malloc_alloc_templateltinstgt::__malloc_alloc_oom_handler 0 template ltint instgt void __malloc_alloc_templateltinstgt::oom_mallocsize_t n void my_malloc_handler void result for //不断尝试释放、配置、再释放、再配置… my_malloc_handler __malloc_alloc_oom_handler if 0 my_malloc_handler __THROW_BAD_ALLOC my_malloc_handler//呼叫处理例程,企图释放内存。
result mallocn //再次尝试配置内存。
if result returnresult template ltint instgt void __malloc_alloc_templateltinstgt::oom_reallocvoid p size_t n void my_malloc_handler void result for //不断尝试释放、配置、再释放、再配置… my_malloc_handler __malloc_alloc_oom_handler if 0 my_malloc_handler __THROW_BAD_ALLOC my_malloc_handler//呼叫处理例程,企图释放内存。
result reallocp n//再次尝试配置内存。
if result returnresult //注意,以下直接将参数 inst 指定为 0。
typedef __malloc_alloc_templatelt0gt malloc_alloc 当 调 用 malloc 和 realloc 申 请 不 到 内 存 空 间 的 时 候 , 会 改 调 用 oom_malloc 和oom_realloc,这两个函数会反复调用用户传递过来的 out of memory handler 处理函数,直到能用 malloc 或者 realloc 申请到内存为止。
如果用户没有传递__malloc_alloc_oom_handler,__malloc_alloc_template 会抛出__THROW_BAD_ALLOC 异常。
所以,内存不足的处理任务就交给类客户去完成。
2.2.6 第二级分配器__default_alloc_template 第二级配置器多了一些机制,避免太多小额区块造成内存的碎片。
小额区块带来的其实不仅是内存碎片而已,配置时的额外负担(overhead)也是一大问题。
所谓的额外负担如下: 这个分配器采用了内存池的思想,有效地避免了内碎片的问题(顺便一句话介绍一下内碎片和外碎片:内碎片是已被分配出去但是用不到的内存空间,外碎片是由于大小太小而无法分配出去的空闲块)。
如果申请的内存块大于 128bytes,就将申请的操作移交__malloc_alloc_template 分配器去处理;如果申请的区块大小小于 128bytes 时,就从本分配器维护的内存池中分配内存。
分配器用空闲链表的方式维护内存池中的空闲空间,为了方便管理,SGI 第二级配置器会主动将任何小额区块的内存需求量上调至 8 的倍数(例如客端要求 30 bytes,就自动调整为 32bytes) 并维护 16 个 free-lists, , 各自管理大小分别为 8 16 24 32 40 48 56 64 72 8088 96 104 112 120 128 bytes 的小额区块。
free-lists 的节点结构如下: union obj union obj free_list_link char client_data1 / The client sees this. / 我们可能会想,为了维护链表,每个节点需要额外的指针(指向下一节点) ,但是这里用的是 union,从第一个字段看,obj 可被视为指针,指向相同形式的另一个 obj,从第二个字段看,指向实际的区块。
一物二用,不会为了维护串行所必须的指针而造成内存浪费。
第二级分配器的部分实现: enum __ALIGN 8//小型区块的上调边界 enum __MAX_BYTES 128//小型区块的上限 enum __NFREELISTS __MAX_BYTES/__ALIGN//free-lists 个数 //以下是第二级配置器。
//注意,无「template 型别参数」 ,且第二参数完全没派上用场。
//第一参数用于多线程环境下。
本书不讨论多线程环境。
template ltbool threads int instgtclass __default_alloc_template private: // ROUND_UP 将 bytes 上调至 8 的倍数。
static size_t ROUND_UPsize_t bytes return bytes __ALIGN-1 amp __ALIGN - 1 private: unionobj //free-lists 的节点构造 union obj free_list_link char client_data1 / The client sees this. / private: // 16 个 free-lists static obj volatilefree_list__NFREELISTS // 以下函式
上一篇:
各种指标源码
下一篇:
选择网络班只有远程教育一种考试方式吗参考资料