1、stl六大部件

  • 容器:各种数据结构,包括vector,list,deque,set,map等等
  • 算法:各种常用算法,sort,search
  • 迭代器:容器和算法之间的粘合器
  • 防函数:类似于函数
  • 配接器:一种修饰容器或者仿函数或者迭代器接口的东西
  • 配置器:负责空间配置和管理。

2、空间配置器:运用层面不需要关注空间配置器,但是在容器背后,空间分配器负责容器中元素空间的分配。不称为内存分配器而称为空间分配器,是因为空间不一定是内存。可以是磁盘或其它辅助存储介质。

一般而言,内容配置操作和释放操作如下:

class Foo{};
Foo* pf = new Foo;
delete pf;
  • new内含两阶段操作:
    • 调用::operator new配置内存。
    • 调用Foo::Foo()构造对象内容。
  • delete同样内含两阶段操作:
    • 先调用Foo::~Foo()将对象析构
    • 调用::operator delete释放内存。

stl将这两个过程分离开来:

  • 内存配置:由alloc::allocate()负责。
  • 内存释放:由alloc::deallocate()负责。
  • 对象构造:  由::construct()负责。
  • 对象析构:由::destory()负责。
allocator::value_type
allocator::pointer
allocator::const_pointer
allocator::reference
allocator::const_reference
allocator::size_type
allocator::difference_type

//一个嵌套的class template,class rebind<U> 拥有唯一成员other,是一个typedef,代表allocator<U>
allocator::rebind

//构造函数
allocator::allocator()
//拷贝构造函数
allocator::allocator(const allocator&)
template <class U> allocator::allocator(const allocator<U>&)
//析构函数
allocator::~allocator

//返回某个对象的地址,等同于&x
pointer allocator::address(reference x) const
const_pointer allocator::address(const_reference x) const

//分配空间,足以容纳n个元素
pointer allocator::allocate(size_type n,)
//归还之前分配的空间
void allocator::deallocate(pointer p,size_type n)
//可分配的最大空间
size_type allocator::max_size() const

//通过x,在p指向的地址构造一个对象。相当于new((void*)p) T(x)
void allocator::construct(pointer p,const T& x)
//析构地址p的对象
void allocator::destroy(pointer p)

std::alloc:分配器位于<memory>中,内含两个文件,负责分离的2阶段操作。

对象构造和析构

相关文件位于<stl_construct.h>

stl规定分配器必须拥有名有construct()和destory()两个成员函数

内存配置和释放

对象构造前的空间配置和内存释放由<stl_alloc.h>负责。设计哲学如下:

  • 向system heap请求空间
  • 考虑多线程状态
  • 考虑内存不足的应变措施
  • 考虑过多小型区块造成的内存碎片问题。

c++的内存分配基本操作是::operator new(),内存释放基本操作是::operator delete(),这两个函数相当于c中的malloc和free函数。

两级分配器:

  • 第一级分配器:直接使用malloc()和free()
  • 第二级分配器
    • 当配置区域超过128byte时,使用第一级分配器
    • 当配置区域小于128byte时,使用第二级分配器。使用了内存池。

无论alloc被定义为第一级或第二级分配器,SGI还为它再包装一个接口,使分配器的接口能够符合STL规格:

template<class T, class Alloc>
class simple_alloc {

public:
    static T *allocate(size_t n)
                {  == 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)
                {  != n) Alloc::deallocate(p, n * sizeof (T)); }
    static void deallocate(T *p)
                { Alloc::deallocate(p, sizeof (T)); }
};

第一级分配器:__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);

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    static void (* __malloc_alloc_oom_handler)();
#endif

public:

static void * allocate(size_t n)
{
    void *result = malloc(n);//第一级分配器直接使用malloc()
    //以下无法满足需求时,改用oom_malloc()
     == result) result = oom_malloc(n);
    return result;
}

static void deallocate(void *p, size_t /* n */)
{
    free(p);//第一级分配器直接使用free()
}

static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
    void * result = realloc(p, new_sz);//第一级分配器直接使用realloc()
    //以下无法满足需求时,改用oom_realloc()
     == result) result = oom_realloc(p, new_sz);
    return result;
}

//以下仿真C++的set_new_handler()。可以通过它指定自己的
//out-of-memory handler
//不能直接运用C++ new-handler机制,因为它并非使用::operator new来分配内存
static void (* set_malloc_handler(void (*f)()))()
{
    void (* old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = f;
    return(old);
}

};

// malloc_alloc out-of-memory handling

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
//初值为0,有待客户设定
template <int inst>
;
#endif

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;
         == 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(void *p, size_t n)
{
    void (* my_malloc_handler)();
    void *result;

    for (;;) {//不断尝试释放、分配、再释放、再分配...
        my_malloc_handler = __malloc_alloc_oom_handler;
         == my_malloc_handler) { __THROW_BAD_ALLOC; }
        (*my_malloc_handler)(); //调用处理例程,企图释放内存
        result = realloc(p, n); //再次尝试分配内存
        if (result) return(result);
    }
}

第二级分配器:__default_alloc_template

第二级分配器多了一些机制,避免太多小额内存造成内存碎片。小额区块存在以下问题

  • 产生内存碎片
  • 额外负担主要指一些区块信息,用以管理内存。区块越小,额外负担所占的比例越大,越显浪费。
  • 当区块大于128bytes,看成大区块
  • 当区块小于128bytes,看成小区块
    • 内存池管理(也称为次层分配):分配一大块内存,并维护对应的自由链表。下次若载有相同大小的内存需求,就直接从free-list中拔出。如果释放小额区块,就由分配器会受到free-list中。维护有16个free-list。各自管理大小分别为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128bytes的小额区块。第二级分配器会自动将任何小区块内存需求量上调至8的倍数。
union obj{
    union obj* free_list_link;
    ];
}

空间分配函数allocate():

  • 若区块大于128bytes,就调用第一级分配器
  • 如区块小于128bytes,检查对应的free-list
    • 若free-list之内有可用的区块,就直接用,如果没有可用区块,就上调至8的倍数。然后调用refill(),准备为free-list重新填充空间。

空间释放函数deallocate():

  • 若区块大于128bytes,就调用第一级分配器
  • 若区块小于128bytes,找出对应的free-list,将区块回收.

重新填充free-list的函数refill():

  • 若free-list中没有可用区块时,会调用chunk_alloc从内存池中申请空间重新填充free-list。缺省申请20个新节点(新区块),如果内存池空间不足,获得的节点数可能小于20.

chunk_alloc()从内存池中申请空间,根据end_free-start_free判断内存池中剩余的空间

  • 剩余空间充足:直接调出20个区块返回给free-lis
  • 如果剩余空间不足以提供20个区块,但足够供应至少1个区块,拨出这不足20个区块的空间
  • 如果剩余空间连一个区块都无法供应,
    • 利用malloc()从heap中分配内存
    • 如果malloc()获取失败,chunk_alloc()就四处寻找有无”尚有未用且区块足够大“的free-list。找到了就挖出一块交出。
    • 如果上一步仍未成功,那么就调用第一级分配器,第一级分配器有out-of-memory处理机制,或许有机会释放其它的内存拿来此处使用。如果可以,就成功,否则抛出bad_alloc异常

迭代器:

  1. value type:指迭代器所指对象的类型
  2. difference type:用以表示两个迭代器之间的距离
  3. pointer:如果value type是T,那么pointer就是指向T的指针
  4. reference:如果value type是T,那么reference就是T的引用
  5. iterator category:迭代器的类型。

<STL源码剖析>配置器的更多相关文章

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

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

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

    本文大致对STL中的空间配置器进行一个简单的讲解,由于只是一篇博客类型的文章,无法将源码表现到面面俱到,所以真正感兴趣的码农们可以从源码中或者<STL源码剖析>仔细了解一下. 1,为什么S ...

  3. 《STL源码剖析》环境配置

    首先,去侯捷网站下载相关文档:http://jjhou.boolan.com/jjwbooks-tass.htm. 这本书采用的是Cygnus C++ 2.91 for windows.下载地址:ht ...

  4. STL"源码"剖析-重点知识总结

    STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...

  5. 【转载】STL"源码"剖析-重点知识总结

    原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...

  6. (原创滴~)STL源码剖析读书总结1——GP和内存管理

    读完侯捷先生的<STL源码剖析>,感觉真如他本人所说的"庖丁解牛,恢恢乎游刃有余",STL底层的实现一览无余,给人一种自己的C++水平又提升了一个level的幻觉,呵呵 ...

  7. STL"源码"剖析

    STL"源码"剖析-重点知识总结   STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...

  8. 《STL源码剖析》相关面试题总结

    原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...

  9. STL源码剖析之序列式容器

    最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的<STL源码剖析>.之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限 ...

随机推荐

  1. SAP MM PR中的Fixed ID字段与MD04里PR单据号后的星号

    SAP MM PR中的Fixed ID字段与MD04里PR单据号后的星号 如下图是我手工使用ME51N 创建的一个采购申请单据, ​ MD04去看这个PR, ​ 这个PR号码后面有一个*号,代表它是一 ...

  2. 吴恩达机器学习笔记 —— 7 Logistic回归

    http://www.cnblogs.com/xing901022/p/9332529.html 本章主要讲解了逻辑回归相关的问题,比如什么是分类?逻辑回归如何定义损失函数?逻辑回归如何求最优解?如何 ...

  3. 极简】如何在服务器上安装SSL证书?

    本文适合任何人了解,图形化操作.下面以腾讯云为例,并且服务器(linux)也安装了宝塔面板. 1.登陆腾讯云账号进入控制台,找到SSL的产品 2.按要求申请并填写表单,记住私钥密码 3.提交后,待腾讯 ...

  4. eclipse安装其他颜色主题包

    eclipse安装其他颜色主题包: 用Help-Install new software安装的时候,work with的URL是 http://eclipse-color-theme.github.c ...

  5. 使用 new XMLHttpRequest() 制作下载文件进度条

    mui 进度控件使用方法: 检查当前容器(container控件)自身是否包含.mui-progressbar类: 当前容器包含.mui-progressbar类,则以当前容器为目标控件,直接显示进度 ...

  6. Django APP打包重用

    引言 有时候,我们需要将自己写的app分发(dist)给同事,分享给朋友,或者在互联网上发布,这都需要打包.分发我们的app. Django的子系统重用是基于app级别的.也就是一个项目可以包含多个互 ...

  7. 如何定位那些SQL产生了大量的redo日志

    在ORACLE数据库的管理.维护过程中,偶尔会遇到归档日志暴增的情况,也就是说一些SQL语句产生了大量的redo log,那么如何跟踪.定位哪些SQL语句生成了大量的redo log日志呢? 下面这篇 ...

  8. mssql sqlserver 视图如何加密,让第三方用户查看不到其中的SQL语句

    转自:http://www.maomao365.com/?p=6719 摘要: 下文讲述视图加密的方法分享,通过此方法可以使视图只可使用,无法获取视图中sql脚本的内容,如下所示: 在创建视图的语法中 ...

  9. Python语法的转义字符

    Python语法的转义字符 转义字符 说 明 \ 续行符 \n 换行符 \0 空  \t 水平制表符,用于横向跳到下一制表位 \'' 双引号 \' 单引号 \\ 一个反斜杠 \f 换页 \0dd 八进 ...

  10. Objective-C简介

    1.OC简介 全称:Objective-C,是扩充C的面向对象编程语言,主要用于iOS和Mac OS开发. C语言的基础上,增加了一层最小的面向对象语法 完全兼容C语言 可以在OC代码中混入C语言代码 ...