STL-空间配置器(allocator)
来源:互联网 发布:mvc php路由文件加载 编辑:程序博客网 时间:2024/05/16 09:52
SGI空间配置器
allocator的标准接口
allocator::value_typeallocator::pointerallocator::const_pointerallocator::referenceallocator::const_referenceallocator::size_typeallocator::diffrence_typeallocator::rebind一个嵌套的class template。class rebind<U>拥有唯一成员other,那是一个typedef,代表allocator<U>allocator::allocator()allocator::allocator(const allocator&)template<class U>allocator::allocator(const allocator<U>&)allocator::~allocator()pointer allocator::address(reference x) const返回某个对象的地址。算式a.address(x)等同于&xconst_pointer allocator::address(const_reference x) constpointer allocator::allocate(size_type n, const void* = 0)void alloctor::deallocate(pointer p, size_type n)size_type allocator::max_size() const返回可成功配置的最大量void allocator::construct(pointer p, const T& x)等同于 new(const void*)p T(x)void allocator::destroy(pointer p)等同于p->~T()
SGI的空间配置器std::alloc
SGI定义了一个名为allocator的配置器,但未使用,而是用了一个名为alloc的配置器。STL allocator中内存配置操作由alloc::allocate()负责,内存释放由alloc::deallocate()负责;对象构造由::construct()负责,对象析构由::destroy()负责。
STL中关于内存分配的相关头文件关系如下图所示
构造和析构工具construct和destroy
构造和析构的两个函数construct和destroy在stl_construct.h文件中,其主要结构如下
construct采用了placement new运算子完成,而destroy则有两个版本,一个就接受一个指针,然后调用其析构函数将其析构掉,另一个接受两个迭代器,将两个迭代器所指范围内的所有对象析构,同时还利用__type_traits判断该型别的析构函数是否trivial,是的话则什么都不做。
空间的分配与释放 std::alloc
对于空间的分配和释放,SGI主要是这样做的:
- 向system heap要求空间
- 考虑多线程状态
- 考虑内存不足时的应变措施
- 考虑过多的小块内存要求而造成的内存碎片问题
针对内存碎片问题,SGI设计了双层级配置器,第一级配置器就直接使用了malloc和free,第二级配置器就视情况采用不同的策略,当配置内存超过128bytes时,则调用第一级配置器,若小于128bytes,便采用内存池方式。
源码中第一级配置器为__malloc_alloc_template,第二级配置器为__default_alloc_template,通过宏来选择定义alloc为哪一级配置器。默认情况下都为第二级
typedef __default_alloc_template<__NODE_ALLOCATOR_THREADS, 0> alloc;
同时,SGI还定义了一个simple_alloc,封装了allocator所需要的接口,STL的容器都使用这个接口。
template<class _Tp, class _Alloc>class simple_alloc {public: static _Tp* allocate(size_t __n) { return 0 == __n ? 0 : (_Tp*) _Alloc::allocate(__n * sizeof (_Tp)); } static _Tp* allocate(void) { return (_Tp*) _Alloc::allocate(sizeof (_Tp)); } static void deallocate(_Tp* __p, size_t __n) { if (0 != __n) _Alloc::deallocate(__p, __n * sizeof (_Tp)); } static void deallocate(_Tp* __p) { _Alloc::deallocate(__p, sizeof (_Tp)); }};
两级配置器的选择和应用关系如下图
第一级配置器__malloc_alloc_template
从源码中可以看到,第一级配置器的allocate,reallocate,deallocate分别调用了malloc,remalloc和free,同时模拟了C++的set_new_handler机制,在内存不足的时候调用由客户端设定的函数,否则直接抛出bad_malloc异常。在内存不足的情况下,allocate和reallocate分别调用了_S_oom_malloc和_S_oom_realloc函数来处理。_S_oom_malloc函数的源码如下
template <int __inst>void* __malloc_alloc_template<__inst>::_S_oom_realloc(void* __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 = realloc(__p, __n); if (__result) return(__result); }}
第二级配置器__default_alloc_template
第二级配置器分配空间时会做一个判断,如果分配的空间大于128bytes,则直接调用第一级分配器,如果小于128bytes,就会采用第二级分配器的内存池管理技术。
第二级的内存池管理主要维护了16个自由空间链表,每个链表依次管理8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128bytes的内存块,每次分配空间时,先把空间大小上调到8的整数倍,然后到相应的链表中去查询是否有空闲的块可用,如果有,则从链表中取出相应的块,(没有的情况后面再介绍);相应的,释放的时候,就将它放回到相应的链表中。
比如下图所示,要分配一个56bytes的空间,首先定位到存储56bytes空闲块的链表头,发现它并非null,那么它指向的第一块空间就是我们所需要的结果(图中红色的块),在取出红色的块之后,我们需要把链表头指向它的下一块(图中虚线所示)。
释放空间时,也一样,先定位到链表头,然后将回收的块作为新的链表头,原来的块作为它的后继。
下面讨论当allocate时发现所处的链表中没有空闲块时,该如何处理。这个时候,就调用了_S_refill()函数,该函数从内存池去取新的空间,默认取得20个新节点,如果内存池空间不足,可能会小于20。内存池主要维护了三个变量:
static char* _S_start_free;static char* _S_end_free;static size_t _S_heap_size;
分别表示内存池当前的起始地址,结束地址和到目前为止,总共分配的堆的大小。到内存池取新的空间时,主要看内存池的剩余空间是否足够(_S_end_free-_S_start_free),然后分别处理。主要工作由_S_chunk_alloc()完成,总的流程如下:
内存基本处理工具
这里的内存处理工具主要是stl_uninitialized.h文件中的uninitialized_copy,uninitialized_fill函数。
uninitialized_copy
uninitialized_copy有两个针对char*和wchar_t*的特化版本,这两个版本都是直接调用了memmove函数;泛化版本如下所示
template <class _InputIter, class _ForwardIter>inline _ForwardIteruninitialized_copy(_InputIter __first, _InputIter __last, _ForwardIter __result){ return __uninitialized_copy(__first, __last, __result, __VALUE_TYPE(__result));}template <class _InputIter, class _ForwardIter, class _Tp>inline _ForwardIter__uninitialized_copy(_InputIter __first, _InputIter __last, _ForwardIter __result, _Tp*){ typedef typename __type_traits<_Tp>::is_POD_type _Is_POD; return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());}
泛化版本通过判断当前迭代器是否是无关紧要的(一些int等内置类型),如果是,则调用copy函数,否则,通过construct在新空间上一步步构造完成。
template <class _InputIter, class _ForwardIter>inline _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last, _ForwardIter __result, __true_type){ return copy(__first, __last, __result);}template <class _InputIter, class _ForwardIter>_ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last, _ForwardIter __result, __false_type){ _ForwardIter __cur = __result; __STL_TRY { for ( ; __first != __last; ++__first, ++__cur) construct(&*__cur, *__first); return __cur; } __STL_UNWIND(destroy(__result, __cur));}
uninitialized_fill
和uninitialized_copy类似,uninitialized_fill会根据当前迭代器的型别分别做不同的处理,如果是无关紧要的类型,就直接调用fill函数,否则,就用construct一步步构造。
template <class _ForwardIter, class _Tp>inline void__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last, const _Tp& __x, __true_type){ fill(__first, __last, __x);}template <class _ForwardIter, class _Tp>void__uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last, const _Tp& __x, __false_type){ _ForwardIter __cur = __first; __STL_TRY {for ( ; __cur != __last; ++__cur) construct(&*__cur, __x); } __STL_UNWIND(destroy(__first, __cur));}template <class _ForwardIter, class _Tp, class _Tp1>inline void __uninitialized_fill(_ForwardIter __first, _ForwardIter __last, const _Tp& __x, _Tp1*){ typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD; __uninitialized_fill_aux(__first, __last, __x, _Is_POD());}template <class _ForwardIter, class _Tp>inline void uninitialized_fill(_ForwardIter __first, _ForwardIter __last, const _Tp& __x){ __uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first));}
- STL(一):allocator 空间配置器
- STL-空间配置器(allocator)
- STL:allocator空间配置器
- SGI STL 空间配置器(allocator)源码剖析
- SGI STL 空间配置器(allocator)源码剖析
- STL之空间配置器allocator
- 【STL】SGI空间配置器 Allocator
- stl之空间配置器Allocator
- STL 空间配置器 allocator<一>
- 空间配置器allocator
- 空间配置器allocator
- STL源码学习之空间配置器allocator【2013.11.15】
- 标准模板库的空间配置器 STL's allocator
- 标准模板库的空间配置器 STL allocator
- STL学习笔记--2、空间配置器 allocator
- SGI STL学习笔记(1):空间配置器(allocator)
- STL源码剖析之空间配置器Allocator
- STL源码剖析 — 空间配置器(allocator)
- 零基础入门深度学习(3) - 神经网络和反向传播算法
- replace防止数据表中重复数据插入
- JavaWeb spring 常见的缺包异常
- java实现Excel导入数据库,数据库中的数据导入到Excel表格中
- 边学NodeMcu边学Lua--GPIO,PWM操作
- STL-空间配置器(allocator)
- How to make the strings upside down
- linux(ubuntu)编译linux内核提示"mkimage" command not found
- Tomcat的性能与最大并发数
- R语言(转载)之par()函数
- Linux驱动手动绑定和解绑定
- HashMap多线程下发生死循环的原因
- A1106. Lowest Price in Supply Chain (25)
- springboot data rest 4