1. allocator 基本介绍html
分配器(allocator))是C ++标准库的一个组件, 主要用来处理全部给定容器(vector,list,map等)内存的分配和释放。C ++标准库提供了默认使用的通用分配器std::allocator,可是,也能够由程序员本身提供自定义分配器。 c++
2. allocator 标准库规范程序员
咱们去看std中的stl分配器实现,会发现不管你的实现思路怎么变,全部模板类中的接口和成员变量都是同样的,那么这是由于C++标准库在制定分配器时,是有提出硬性标准的,具体接口和成员变量以下: 缓存
STD 标准规范(GNU ISO C++ Library 5.2.1):多线程
typedef size_t size_type; typedef ptrdiff_t difference_type; typedef _Tp* pointer; typedef const _Tp* const_pointer; typedef _Tp& reference; typedef const _Tp& const_reference; typedef _Tp value_type; void construct(pointer __p, const _Tp& __val) { ::new((void *)__p) value_type(__val); } void destroy(pointer __p) { __p->~_Tp(); } size_type max_size() const _GLIBCXX_USE_NOEXCEPT { return size_t(-1) / sizeof(_Tp); } address(const_reference __x) const _GLIBCXX_NOEXCEPT deallocate(pointer, size_type); allocate(size_type __n, const void* = 0); template<typename _Tp1> struct rebind { typedef allocator<_Tp1> other; };
对于上面这一段接口和变量,其中一些在其余容器的分析中,咱们会常常看到,下面对于其中有疑问的点咱们来解释一下:性能
size_type:this
为 unsigned 类型 , 表示容器中元素长度或者下标,例:vector
difference_type:.net
为 signed 类型 , 表示迭代器差距, vector
size_t(-1):
size_t 为 unsigned 类型,传入 -1 得到size_t该系统的最大值。
3. GNU ISO C++ Library 中STL分配器实现
1. 默认分配器:
按照标准规范,标准库中stl实现的分配器,对外接口,成员变量几乎都同样,只是接口内部实现有区别,那么咱们看一下具体实现流程, 首先看一下容器默认的分配器std::allocator<_Tp>。 看代码咱们会发现,默认分配器真正的实现是在new_allocator.h头文件中作的,头文件具体调用顺序为:allocator.h -> c++allocator.h -> new_allocator.h, 看代码咱们知道,在前面两个头文件中基本没作什么,真正的实现为模板类new_allocator。 关键代码以下所示:
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION template<typename _Tp> class new_allocator { public: typedef _Tp* pointer; typedef const _Tp* const_pointer; // NB: __n is permitted to be 0. The C++ standard says nothing // about what the return value is when __n == 0. pointer allocate(size_type __n, const void* = 0) { if (__n > this->max_size()) std::__throw_bad_alloc(); return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); } // __p is not permitted to be a null pointer. void deallocate(pointer __p, size_type) { ::operator delete(__p); } } _GLIBCXX_END_NAMESPACE_VERSION } // namespace
咱们看一下分配和释放的接口allocate和deallocate,实现上只是单纯的将::operator new和::operator delete进行了一下封装,没用作特殊处理。
固然,若是咱们不特别说明,直接在Linux系统下使用标准C++的stl容器,在为容器元素分配内存时,使用的方式就是相似于正常的new和delete,这种方式对于不频繁分配,而且一次分配大块内存的使用状况是适用的,典型的容器像vector和deque。
2. 拓展分配器:
咱们继续查看STL源码会发现,除了默认分配器,gnu下的STL还实现了一些特殊的分配器,像__pool_alloc,__mt_alloc,array_allocator,malloc_allocator (在源码的/c++/ext/ 目录下)
__pool_alloc :比较出名的SGI内存池分配器,侯捷老师在STL源码剖析中着重分析的,后面会专门加一章来进行讲解
__mt_alloc : 多线程内存池分配器,具体能够看一下该博主的连接讲解,仍是比较详细的
array_allocator : 全局内存分配,只分配不释放,交给系统来释放
malloc_allocator : 封装了一下std::malloc和std::free
4. 自定义分配器 (allocator)
咱们为何要自定义分配器,废话,主要缘由固然是由于性能了。利用自定义分配器能够显著改善程序性能及分配器使用便利性。
对于默认分配器,也就是咱们常使用的new和malloc,若是遇到须要频繁分配小块内存对象的状况,由于须要不停的向系统锁要内存,那么将使得分配过程变得很慢;还有就是致使出现过多的内存碎片;以及一些极端状况,分配的内存过于小且数量庞大,致使分配一次内存,附带的内存消耗反而更大,形成内存的浪费
主流提升性能的方式是建立基于内存池的分配器,每次在容器中插入删除元素,不是分配内存,而是分配程序启动时预先分配的大块内存(内存池)。这种自定义分配器,经过简单的从池中返回指向内存的指针来提供单独的分配请求。还有就是能够推迟实践的内存释放,直到内存池生命周期结束
C++之父 Bjarne stroustrup 提到,自定义分配器的三个主要应用,即内存池分配器,共享内存分配器和垃圾收集(gc)分配器
垃圾回收应该就是智能指针,本身控制资源的回收;内存池则主要负责对性能的提高;共享内存分配器则是对特殊缓存区的处理。 后续会一一分析介绍!
具体连接:
SGI 内存池分配器
智能指针
共享内存分配-hashmap
多线程分配器
2018年9月8日00:18:28