<STL源码剖析>配置器
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异常
迭代器:
- value type:指迭代器所指对象的类型
- difference type:用以表示两个迭代器之间的距离
- pointer:如果value type是T,那么pointer就是指向T的指针
- reference:如果value type是T,那么reference就是T的引用
- iterator category:迭代器的类型。
<STL源码剖析>配置器的更多相关文章
- STL源码剖析 — 空间配置器(allocator)
前言 以STL的实现角度而言,第一个需要介绍的就是空间配置器,因为整个STL的操作对象都存放在容器之中. 你完全可以实现一个直接向硬件存取空间的allocator. 下面介绍的是SGI STL提供的配 ...
- STL源码剖析之空间配置器
本文大致对STL中的空间配置器进行一个简单的讲解,由于只是一篇博客类型的文章,无法将源码表现到面面俱到,所以真正感兴趣的码农们可以从源码中或者<STL源码剖析>仔细了解一下. 1,为什么S ...
- 《STL源码剖析》环境配置
首先,去侯捷网站下载相关文档:http://jjhou.boolan.com/jjwbooks-tass.htm. 这本书采用的是Cygnus C++ 2.91 for windows.下载地址:ht ...
- STL"源码"剖析-重点知识总结
STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略多 :) 1.STL概述 STL提供六大组件,彼此可以组合 ...
- 【转载】STL"源码"剖析-重点知识总结
原文:STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点 ...
- (原创滴~)STL源码剖析读书总结1——GP和内存管理
读完侯捷先生的<STL源码剖析>,感觉真如他本人所说的"庖丁解牛,恢恢乎游刃有余",STL底层的实现一览无余,给人一种自己的C++水平又提升了一个level的幻觉,呵呵 ...
- STL"源码"剖析
STL"源码"剖析-重点知识总结 STL是C++重要的组件之一,大学时看过<STL源码剖析>这本书,这几天复习了一下,总结出以下LZ认为比较重要的知识点,内容有点略 ...
- 《STL源码剖析》相关面试题总结
原文链接:http://www.cnblogs.com/raichen/p/5817158.html 一.STL简介 STL提供六大组件,彼此可以组合套用: 容器容器就是各种数据结构,我就不多说,看看 ...
- STL源码剖析之序列式容器
最近由于找工作需要,准备深入学习一下STL源码,我看的是侯捷所著的<STL源码剖析>.之所以看这本书主要是由于我过去曾经接触过一些台湾人,我一直觉得台湾人非常不错(这里不涉及任何政治,仅限 ...
随机推荐
- CSS字体样式属性
font-size 字号大小 一般推荐使用相对长度(px ,em),不推荐使用绝对长度(in,cmm,mm,pt) font-family 字体 1.可以同时指定多个字体,中间用英文状态的逗号隔开,英 ...
- 矢量图面层和线层相交得到相交后的线层文件(gis相交)
目的:将arcgis里的面层和线层相交(重叠)部分的线单独生成一个shp文件,用于道路路网密度计算等. 注意:进行相交运算后生成的是线要素文件,相当于把面线相交部分的线单独拿了出来. 操作例子:将图示 ...
- Android为TV端助力 双缓存机制
废话不多说,直接贴代码! 所谓的双缓存,第一就是缓存在内存里面,第二就是缓存在SD卡里面,当你需要加载数据时,先去内存缓存中查找,如果没有再去SD卡中查找,并且用户可以自选使用哪种缓存! 缓存内存和缓 ...
- LRU(最近最少使用淘汰算法)基本实现
LRU(Least Recently Used) 出发点:在页式存储管理中,如果一页很长时间未被访问,则它在最近一段时间内也不会被访问,即时间局部性,那我们就把它调出(置换出)内存. 为了实现LRU ...
- 卸载(uninstalled)Mac os Jenkins pkg 安装包
有些小伙伴不熟悉Jenkins, 在mac上安装,会选择pkg 安装包, 安装后又想卸载,苦于卸载不干净,今天给到一个命令即可搞定. 对应qq群号:616961231打开终端输入下面命令'/Libra ...
- mysql之数据备份与恢复
本文内容: 复制文件法 利用mysqldump 利用select into outfile 其它(列举但不介绍) 首发日期:2018-04-19 有些时候,在备份之前要先做flush tables , ...
- 惰性求值——lodash源码解读
前言 lodash受欢迎的一个原因,是其优异的计算性能.而其性能能有这么突出的表现,很大部分就来源于其使用的算法--惰性求值. 本文将讲述lodash源码中,惰性求值的原理和实现. 一.惰性求值的原理 ...
- (面试题)python面试题集锦-附答案
1.一行代码实现1-100的和 sum_1_100 = sum(range(1, 101)) 2.如何在一个函数内修改全局变量的值 a = 100 def foo(): global a a = 30 ...
- Linux中DNS的设置
1.查看本机的域名 hostname 2.修改DNS 临时修改: hostname desktop0.example.com 永久修改: hostnamectl set-hostname deskto ...
- You (root) are not allowed to access to (crontab) because of pam configuration
巡检发现一台Linux服务器上的作业没有如期发送邮件,登录服务器检查后发现作业并没有执行,于是检查一下crontab的设置.结果发现如下错误: [root@mylnx2 ~]# crontab -l ...