【STL源码剖析读书笔记】【第2章】空间配置器
来源:互联网 发布:poi导出excel到数据库 编辑:程序博客网 时间:2024/05/16 09:18
1、 allocator是空间配置器而不是内存配置器,空间不一定是内存,也可以是磁盘或其它辅助存储介质。但SGI STL提供的配置器配置的对象是内存。
2、 SGI标准的空间配置器,std::allocator
SGI定义了一个符合部分标准,名为allocator的配置器,效率不高,只把c++的::operator new和::operator delete做了一层薄薄的包装,SGI没有用过。
3、 c++用new构造一个对象时,包含两阶段操作:(1)调用::operator new配置内存;(2)调用该对象的构造函数构造对象内容。delete销毁一个对象时,也包含两阶段操作:(1)调用该对象的析构函数将对象析构;(2)调用::operator delete释放内存。
STL allocator将上述两阶段操作区分开来。内存配置由alloc::allocator()负责,内存释放操作由alloc::deallocator()负责;对象构造由::constructor()负责,对象析构由::destroy()负责。
4、 构造和析构基本工具
对象的构造:
template <class T1, class T2>inline void construct(T1* p, const T2& value) { new (p) T1(value);}
上述函数接受一个指针p和一个初值value,用定位new运算子将初值设定到指针所指的空间上。
对象的析构:
template <class T> //第一版本inline void destroy(T* pointer) { pointer->~T();}template <class ForwardIterator> //第二版本inline void destroy(ForwardIterator first, ForwardIterator last) { __destroy(first, last, value_type(first));}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, ForwardIterator, __true_type) {}
上述destro()的第一版本接受接受一个指针,将该指针所指的对象析构掉。第二版本接受first和last两个迭代器,将这两个迭代器范围内的对象析构掉。在第二版本中运用了traits编程技法,traits会得到当前对象的一些特性,再根据特性的不同分别对不同特性的对象调用相应的方法。在第二版本中,STL会分析迭代器所指对象的has_trivial_destructor特性的类型(只有两种:__true_type和__false_type),如果是__true_type,STL就什么都不做;如果是__false_type,就会调用每个对象的析构函数来销毁这组对象。
5、内存的配置
SGI设计了双层配置器,第一级配置器直接使用malloc()和free(),第二级配置器采取以下策略:当配置区块超过128bytes时,调用第一级配置器;当配置区块小于128bytes时,采用内存池方式。
6、 第一级配置器
static void * allocate(size_t n){ void *result = malloc(n);//直接使用malloc() if (0 == 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() if (0 == result) result = oom_realloc(p, new_sz); return result;}
当alloc()和realloc()申请不到内存时,会调用oom_malloc()和oom_realloc(),这两个函数不断调用“内存不足处理函数”,直到获得足够内存为止。如果用户没有传递“内存不足处理函数”,会抛出__THROW_BAD_ALLOC异常。
7、 第二级配置器
第二级配置器的做法:如果申请内存大于128bytes时,就用第一级配置器处理。小于128 bytes时,以内存池管理:每次配置一大块内存,并维护对应的自由链表。
具体分配内存过程:
allocate()函数处理过程:
1) 如果申请内存大于128 bytes,就调用第一级配置器,否则说明申请内存小于128 bytes,转到2)
2) 根据申请内存的大小n在16个free lists中找出其对应的my_free_list
3) 如果对应的my_free_list中没有空闲区块,分配器首先将申请内存的大小上调至8的倍数n,调用refill(),准备重新填充my_free_list
4) 否则说明有可用的空闲区块,更新my_free_list并将第一块空闲区块返回
refill()函数的处理过程:
1) 调用chunk_alloc()函数申请20*n的内存空间(不一定取得到)
2) 如果只获得一个大小为n的区块,这个区块就分配给调用者,否则从获得的区块中取出一块分配给调用者,其余的用my_free_list串接起来
chunk_alloc()函数处理过程:
1) 如果内存池剩余空间大于或等于20*n的内存空间,则从这个空间中取出n*20大小的内存空间,更新start_free并返回申请到的内存空间的起始地址,否则转到2)
2) 如果内存池剩余空间足够分配一个及以上的区块,则分配整数倍于n的内存空间,更新start_free,由nobjs返回实际分配到的区块个数,并返回申请到的内存空间的起始地址,否则转到3)
3) 内存池中无法提供一个大小为n的区块,此时如果内存池中还有一些残余内存(这些内存大小小于n),则将这些内存插入到其对应大小的空闲分区链中
4) 调用malloc向运行时库申请大小为(2*20*n + 附加量)的内存空间, 如果申请成功,更新start_free,end_free和heap_size,并递归调用chunk_alloc(),修正nobjs,否则转到5)
5) 4)中调用malloc失败,这时分配器依次遍历区块足够大的freelists,只要有一个未用区块,就释放该区块,递归调用chunk_alloc(),修正nobjs
6) 如果出现意外,到处都没有内存可用了,则调用第一级配置器,看out-of-memory机制能否尽点力
对应第二级配置器的allocate()函数处理过程的第4步:
对应第二级配置器的内存池操作:
8、内存的释放
具体内存释放过程:
先判断要释放的内存区块的大小,大于128 bytes就调用第一级配置器释放内存,否则要释放的内存区块小于128 bytes,就找出对应的free_list,将区块回收。
9、内存基本处理工具
STL还提供了3个内存处理工具:uninitialized_copy(),uninitialized_fill()和uninitialized_fill_n()函数,分别对应copy(),fill()和fill_n()函数。这三个
函数都具有” commit or rollback ”语意,意思是要么构造出所有元素,要么一个也不构造。
三个内存基本函数的泛型版本与特化版本:
- 【STL源码剖析读书笔记】【第2章】空间配置器
- 《STL源码剖析》读书笔记---第2章 空间配置器
- STL源码剖析 - 第2章 空间配置器
- STL空间配置器--《STL源码剖析》读书笔记
- 《STL源码剖析》读书笔记二--空间配置器
- STL 源码剖析读书笔记一:空间配置器
- 《STL源码剖析》学习笔记-第2章 空间配置器
- STL源码剖析_读书笔记:第二章 空间配置器 一级和二级配置器篇
- 《STL源码剖析》STL空间配置器
- 《STL源码剖析》读书笔记--第二章 空间配置器(allocator)
- STL源码剖析_读书笔记:第二章 空间配置器 内存池篇
- STL源码剖析_读书笔记:第二章 空间配置器 构建简单的空间配置器篇
- STL源码剖析---空间配置器
- STL源码剖析---空间配置器
- STL源码剖析之空间配置器
- STL源码剖析---空间配置器
- STL源码剖析---空间配置器
- STL源码剖析:空间配置器
- 创建自定义 AngularJS 指令:Part 4 transclude和restrict介绍
- Codevs3116 高精度练习之加法
- 服务器使用Gzip压缩数据,加快网络传输(Java 例子)
- springMVC学习(sringAOP)
- iOS中的属性传值
- 【STL源码剖析读书笔记】【第2章】空间配置器
- 剑指Offer之 - 旋转数组的最小数字
- Ubuntu 配置 Tomcat
- 【bzoj1040】【zjoi2008】骑士(树形dp)
- android EditText使用
- Ubuntu 14.04 安装mysql和简单操作
- 5.18作业程序导图
- 未定义行为
- 使用GraphViz画caffe的网络结构图