STL的空间配置器作为STL六大部件的重要组成部分,它总是隐藏在一切组件的背后.它主要负责动态空间的分配、释放等管理工作。整个STL的操作对象(所有的数值)都存放在容器之内,而容器一定需要配置空间以置放资料。而这就是空间配置器(allocator)的职责了.

一.SGI的空间配置器—std::alloc

STL allocator将内存分配/释放对象构造/析构区分开来.内存配置操作由alloc::allocate()负责,内存释放由alloc::deallocate()负责;对象构造操作由::construct()负责,对象析构操作由::destroy()负责.

STL标准表格告诉我们,配置器定义于<memory>中,SGI<memory>内含两个文件:

#include <stl_alloc.h>  //负责内存空间的配置与释放

  #include <stl_construct.h> //负责对象内容的构造与析构

1.构造和析构基本工具:construct()和destroy()

#include <new.h> //欲使用placement new,需先包含此文件

template<class T1,class T2>
inline void construct(T1* p,const T2& value){
new (p) T1(value); //placement new;调用T1::T1(value);
} //以下是destroy()第一版本,接受一个指针
template<class T>
inline void destroy(T* pointer){
pointer->~T();//调用dtor ~T()
} template<class ForwardIterator>
inline void destroy(ForwardIterator first,ForwardIterator last){
__destroy(first,last,value_type(first));
} //判断元素的数值型别(value type)是否有trivial destructor
template <class ForwardIterator,class T>
inline void destroy(ForwardIterator first,ForwardIterator last,T*){
typedef typename __type_trait<T>::has_trivial_destructor trivial_destructor;
__destroy_aux(first,last,trivial_destructor());
} //如果元素的数值型别(value_type)有non-trivial destructor
template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first,ForwardIterator last,__false_type){
for(;first<last;first++) destroy(&*first);
} template <class ForwardIterator>
inline void __destroy_aux(ForwardIterator first,ForwardIterator last,__true_type){} inline void destroy(char*,char*){}
inline void destroy(wchar_t*,wchar_t*){}

2.空间的配置与释放

     SGI是以malloc()和free()完成内存的配置与释放.考虑到小型区块所可能造成的内存破碎问题,SGI设计了双层级配置器。第一级配置器直接使用malloc()和free(),第二级配置器则视情况采用不同的策略:当配置区块超过128bytes时,视之为"足够大",便调用第一级配置器;当配置区块小于128bytes时,视之为"过小",为了降低额外负担,便采用memory pool整理方式,而不再求助于第一级配置器。

无论alloc被定义为第一级或第二级配置器,SGI还为它再包装了一个接口,使配置器的接口更符合STL规格。

template <class T,class Alloc>
class simple_alloc{
public:
static T* allocate(size_t n){
return ==n?:(T*)Alloc::allocate(n*sizeof(T));
}
static T* allocate(void){
return (T*)Alloc::allocate(sizeof(T));
}
static void deallocate(T* p,size_t n){
if(n!=) Alloc::deallocate(p,n*sizeof(T));
} static void deallocate(T* p){
Alloc::deallocate(p,sizeof(T));
}
};

其内部四个成员函数其实都是单纯的转调用,调用传递给配置器(可能是第一级也可能是第二级)的成员函数。SGI STL容器全部都是使用这个simple_alloc接口。

  2.1 第一级配置器 __malloc_alloc_template剖析

//注意,无"template型别参数",inst完全没有派上用场
template<int inst>
class __malloc_alloc_template{
private:
//以下都是函数指针,所代表的函数将用来处理内存不足的情况
//oom:out of memory
static void* oom_malloc(size_t);
static void* oom_realloc(void*,size_t);
static void (*__malloc_alloc_oom_handler)(); public:
static void* allocate(size_t n){
void* result=malloc(n);
if(==result) result=oom_malloc(n);
return result;
} static void deallocate(void* p,size_t /*n*/){
free(p);
} static void* reallocate(void* p,size_t old_sz,size_t new_sz){
void* result=realloc(p,new_sz);
if(==result) oom_realloc(p,new_sz);
return result;
} //以下仿真C++的set_new_handler()
static void (*set_malloc_handler(void (*f)()))(){
void (*old)()=__malloc_alloc_oom_handler;
__malloc_alloc_oom_handler=f;
return (old);
}
}; void (*__malloc_alloc_template<int>::__malloc_alloc_oom_handler)()=; template<int inst>
void* __malloc_alloc_template<inst>::oom_malloc(size_t n){
void (*my_malloc_handler)();
void* result; for(;;){ //不断尝试释放、配置、释放、配置...
my_malloc_handler=_malloc_alloc_oom_handler;
if(==my_malloc_handler) {__THROW_BAD_ALLOC;}
(*my_malloc_handler)();//调用处理例程,企图释放内存
result=malloc(n); //再次尝试分配内存
if(result) return (result);
}
} template<int inst>
void* __malloc_alloc_template<inst>::oom_realloc(size_t n){
void (*my_malloc_handler)();
void* result; for(;;){ //不断尝试释放、分配、释放、分配...
my_malloc_handler=_malloc_alloc_oom_handler;
if(==my_malloc_handler) {__THROW_BAD_ALLOC;}
(*my_malloc_handler)();//调用处理例程,企图释放内存
result=realloc(p,n); //再次尝试分配内存
if(result) return (result);
}
}

所谓c++ new handler机制是,当系统在内存配置需求无法被满足时,调用一个你指定的函数。也就是说,一旦::operator new无法完成任务,在丢出std::bad_alloc异常状态时,会先调用用户所指定的例程。

  2.1 第二级配置器 __default_alloc_template剖析

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

//free-lists的节点结构如下:
union obj{
union obj* free_list_link;
char client_data[]; //The client sees this
};

第二级配置器的部分源码:

//free-lists的节点结构如下:
union obj{
union obj* free_list_link;
char client_data[]; //The client sees this
}; enum {__ALIGN=};//小型区块的上调边界
enum {__MAX_BYTES=}; //小型区块的上限
enum {__NFREELISTS=__MAX_BYTES/__ALIGN}; //free-lists的个数 //以下是第二级配置器
template <bool threads,int inst>
class __default_alloc_template{
private:
//ROUND_UP()将bytes上调至8的倍数
static size_t ROUND_UP(size_t bytes){
return ((bytes)+__ALIGN-) & ~(__ALIGN-));
} private:
union obj{ //free-lists的节点构造
union obj* free_list_link;
char client_data[];
}; private:
//16个free-lists
static obj* volatile free_list[__NFREELISTS];
//以下函数根据区块大小,决定使用第n号free-lists.n从1开始
static size_t FREELIST_INDEX(size_t bytes){
return ((bytes)+__ALIGN-)/__ALIGN-);
} //返回一个大小为n的对象,并可能加入大小为n的其他区块到free list
static void* refill(size_t n);
//配置一大块空间,可容纳nobjs个大小为"size"的区块
static char* chunk_alloc(size_t size,int &nobjs); //chunk allocation state
static char* start_free;//内存池起始位置
static char* end_free;
static size_t heap_size; public:
static void* allocate(size_t n){}
static void deallocate(void* p,size_t n){}
static void* reallocate(void* p,size_t old_sz,size_t new_sz);
}; //以下是static data memeber的定义与处置设定
template <bool threads,int inst>
char* __default_alloc_template<threads,inst>::start_free=; template <bool threads,int inst>
char* __default_alloc_template<threads,inst>::end_free=; template <bool threads,int inst>
size_t __default_alloc_template<threads,inst>::heap_size=;

STL-空间配置器(allocator)的更多相关文章

  1. 【转】STL空间配置器

    STL空间配置器(allocator)在所有容器内部默默工作,负责空间的配置和回收.STL标准为空间配置器定义了标准接口(可见<STL源码剖析>P43).而具体实现细节则由各编译器实现版本 ...

  2. C++ STL学习之 空间配置器(allocator)

    众所周知,一般情况下,一个程序包括数据结构和相应的算法,而数据结构作为存储数据的组织形式,与内存空间有着密切的联系. 在C++ STL中,空间配置器便是用来实现内存空间(一般是内存,也可以是硬盘等空间 ...

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

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

  4. C++ 空间配置器(allocator)

    C++ 空间配置器(allocator) 在STL中,Memory Allocator 处于最底层的位置,为一切的 Container 提供存储服务,是一切其他组件的基石.对于一般使用 STL 的用户 ...

  5. 咬碎STL空间配置器

    STL空间配置器 一.开场白: 给我的感觉就是,了解是空间配置器的功能,是那么的明了:在看原理,我还是很开心:接下来是360度大转变: 那么长的变量或者函数命名.那么多的宏.不爽,不过,遇上我这种二货 ...

  6. 【陪你系列】5 千字长文+ 30 张图解 | 陪你手撕 STL 空间配置器源码

    大家好,我是小贺. 点赞再看,养成习惯 文章每周持续更新,可以微信搜索「herongwei」第一时间阅读和催更,本文 GitHub https://github.com/rongweihe/MoreT ...

  7. stl空间配置器线程安全问题补充

    摘要 在上一篇博客<STL空间配置器那点事>简单介绍了空间配置器的基本实现 两级空间配置器处理,一级相关细节问题,同时简单描述了STL各组件之间的关系以及设计到的设计模式等. 在最后,又关 ...

  8. STL空间配置器

    1.什么是空间配置器? 空间配置器负责空间配置与管理.配置器是一个实现了动态空间配置.空间管理.空间释放的class template.以内存池方式实现小块内存管理分配.关于内存池概念可以点击:内存池 ...

  9. STL空间配置器那点事

    STL简介 STL(Standard Template Library,标准模板库),从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其 ...

  10. STL空间配置器解析和实现

    STL空间配置器的强大和借鉴作用不言而喻,查阅资料,发现了Dawn_sf已经对其有了极其深入和详细的描述,所以决定偷下懒借用其内容,只提供自己实现STL空间配置器的源码,具体解析内容参考:(一)STL ...

随机推荐

  1. Hibernate的查询语言之HQL(一)——快速入门

    Hibernate提供异常强大的查询体系,使用Hibernat有多种查询方式可以选择:即可以使用Hibernate的HQL查询,也可以使用条件查询,甚至可以使用原生的SQL查询语句.不仅如此, Hib ...

  2. 手机Android音视频采集与直播推送,实现单兵、移动监控类应用

    从安卓智能手机.平板,到可穿戴的Android Ware.眼镜.手表.再到Android汽车.智能家居.电视,甚至最近看新闻,日本出的几款机器人都是Android系统的,再把目光放回监控行业,传统监控 ...

  3. 多线程Two-Phase Termination Pattern两阶段终止模式

    一 Two-Phase Termination Pattern Two-Phase Termination Pattern,指的就是当希望结束一个线程的时候,送出一个终止请求,但是不会马上停止,做一些 ...

  4. Spice代码阅读一:Spice Client 与 Spice Server 通道建立过程

    文件 方法 描述 Application.cpp init_globals() 初始化Log,ssl库,canvas(或opengl canvas)和quic压缩库 Process_cmd_line( ...

  5. C# 关键字--using

    using 关键字有两个主要用途:  (一).作为指令,用于为命名空间创建别名或导入其他命名空间中定义的类型.  (二).作为语句,用于定义一个范围,在此范围的末尾将释放对象. using指令    ...

  6. 桌面环境与桌面搜索Desktop Search tools

    最近一段时间工作重心都将放在Linux下Desktop search(桌面搜索)框架的研发上.因此对desktop search进行了初步的调研.本文将从下面三个方面展开: Linux桌面环境(Des ...

  7. 杭电 HDU ACM 1698 Just a Hook(线段树 区间更新 延迟标记)

    欢迎"热爱编程"的高考少年--报考杭州电子科技大学计算机学院 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memor ...

  8. DecimalFormat用法

    DecimalFormat用法   DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字. DecimalFormat 包含一个模式 和一组符号 符号含义: ...

  9. 自定义控件(视图)2期笔记05:自定义控件之继承自View(滑动开关)

    1.  开关按钮点击效果,如下: 2. 继承已有View实现自定义View 3. 下面通过一个案例实现滑动开关的案例: (1)新建一个新的Android工程,命名为" 开关按钮", ...

  10. MM32Flash读写操作(兼容STM32)

    MM32Flash读写操作(兼容STM32) Flash基础描述 思维导图 编程实现读写操作 主函数结构 #include "delay.h" #include "sys ...