STL源码剖析之空间配置器Allocator
来源:互联网 发布:印度种姓制度现状知乎 编辑:程序博客网 时间:2024/04/28 18:48
Object a = new Object();
delete a;
一般地,对象的构造过程包含两步:(1)调用运算符new进行空间分配;(2)调用构造函数构造对象内容。对象的析构函数也包含两步:(1)调用对象的析构函数;(2)调用运算符delete释放内存。
四、空间释放函数
五、重新填充空间
六、内存池
delete a;
一般地,对象的构造过程包含两步:(1)调用运算符new进行空间分配;(2)调用构造函数构造对象内容。对象的析构函数也包含两步:(1)调用对象的析构函数;(2)调用运算符delete释放内存。
STL中内存操作由alloc:allocate()完成,它是对运算符new的封装,内存释放由alloc:deallocate()完成,它是对运算符delete的封装,对象的构造函数由construct()完成,对象的析构由destroy()完成。
头文件:
#include<stl_alloc.h>//allocate(),deallocate()#include<stl_construct.h>//construct(),destroy()
一、构造与析构
源码如下:
//构造函数,接受两个参数template <class _T1, class _T2>inline void _Construct(_T1* __p, const _T2& __value) { new ((void*) __p) _T1(__value); //调用_T1(value)}//构造函数,接受一个参数template <class _T1>inline void _Construct(_T1* __p) { new ((void*) __p) _T1(); //调用_T1()}//Destroy第一个版本,传入一个指针template <class _Tp>inline void _Destroy(_Tp* __pointer) { __pointer->~_Tp();//调用~T()}//如果用户不定义析构函数,系统默认调用自己的析构函数,则称trivial destructor,调用自定义的析构成为non-trivial destructor//如果元素类型为non-trivial destructor,利用迭代器析构template <class _ForwardIterator>void__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type){ for ( ; __first != __last; ++__first) destroy(&*__first);}//如果元素类型为trivial destructor,不做任何事template <class _ForwardIterator> inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}//判断元素类别是否有trivial destructortemplate <class _ForwardIterator, class _Tp>inline void __destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*){ typedef typename __type_traits<_Tp>::has_trivial_destructor _Trivial_destructor; __destroy_aux(__first, __last, _Trivial_destructor());}//Destroy第二个版本,接受两个迭代器,根据元素类别,调用相应析构template <class _ForwardIterator>inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) { __destroy(__first, __last, __VALUE_TYPE(__first));}//destroy特化版,不做任何操作inline void _Destroy(char*, char*) {}inline void _Destroy(int*, int*) {}inline void _Destroy(long*, long*) {}inline void _Destroy(float*, float*) {}inline void _Destroy(double*, double*) {}#ifdef __STL_HAS_WCHAR_Tinline void _Destroy(wchar_t*, wchar_t*) {}#endif /* __STL_HAS_WCHAR_T */
_Construct:主要是将value赋值给分配的指针空间。
_Destroy:(vision 1)参数为指针,直接调用析构函数。
(vision 2)参数为两个迭代器,根据对象的类型调用相应的析构函数,若为trivial destructor没有任何操作,若为non-trivial destructor则逐个析构掉[first,last)范围中的对象。主要是对效率的优化,防止范围过大,效率低下。
二、空间的申请和释放
第一配置器_malloc_alloc_template的剖析
template <int __inst>class __malloc_alloc_template {//oom : out of memoryprivate://定义处理内存不足的指针 static void* _S_oom_malloc(size_t); static void* _S_oom_realloc(void*, size_t);#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG static void (* __malloc_alloc_oom_handler)();#endifpublic: static void* allocate(size_t __n) { void* __result = malloc(__n);//直接调用malloc if (0 == __result) __result = _S_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);//直接调用relloc if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);//失败交给处理函数 return __result; }//自定义自己的处理函数 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_BUGtemplate <int __inst>void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;#endiftemplate <int __inst>void*__malloc_alloc_template<__inst>::_S_oom_malloc(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 = malloc(__n); if (__result) return(__result); }}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); }}typedef __malloc_alloc_template<0> malloc_alloc;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,free,realloc来进行内存配置,释放,再配置。如果malloc与relloc不成功则调用oom_malloc和oom_realloc进行内存处理。
第二级配置器_defualt_alloc_template的剖析#if defined(__SUNPRO_CC) || defined(__GNUC__)// breaks if we make these template class members: enum {_ALIGN = 8};//小区块上调边界 enum {_MAX_BYTES = 128};//小区块上界 enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN#endiftemplate <bool threads, int inst>class __default_alloc_template {private: static size_t _S_round_up(size_t __bytes) //将__bytes上调8的倍数 { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }__PRIVATE: union _Obj {//free-list结点构造 union _Obj* _M_free_list_link; char _M_client_data[1]; /* The client sees this. */ };private:# if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC) static _Obj* __STL_VOLATILE _S_free_list[]; // Specifying a size results in duplicate def for 4.1# else static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; # endif static size_t _S_freelist_index(size_t __bytes) {//根据区块大小决定使用第n号的free-list return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1); } // 返回一个大小为n的对象,可能加入大小为n的其他区块到free-list static void* _S_refill(size_t __n); // 配置一大块内存,可容纳nobjs个大小为size的区块 // 如果配置nobjs个区块有所不便则nobjs会降低 static char* _S_chunk_alloc(size_t __size, int& __nobjs); // 区块分配状态 static char* _S_start_free;//内存起始位置 static char* _S_end_free;//内存结束位置 static size_t _S_heap_size;//堆大小第二级配置器处理避免了小额区块造成的内存碎片,处理方式为:如果内存过大(超过128字节)交个第一级配置器处理,小于128字节时交由内存池来处理。每次分配一大块内存时都要交由free-list,如果有大小相同的内存需求时就在free-list中申请,有小额内存释放是增加到free-list中。
三、空间配置函数
第二级配置器拥有一个接口allocate(),主要作用是判断内存是否超过128字节,超过交由第一级配置器处理,否则从free-list中提出。如果free-list没有可用内存块则调整 内存边界为8倍数,调用refill()填充空间。
/* __n must be > 0 */ static void* allocate(size_t __n) { void* __ret = 0; if (__n > (size_t) _MAX_BYTES) {//判断__n是否大于128字节 __ret = malloc_alloc::allocate(__n);//大于交由第一级配置器处理 } else {//寻找free-list最适当的一个 _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n); _Obj* __RESTRICT __result = *__my_free_list; if (__result == 0)//没有找到free-list,调用refill填充 __ret = _S_refill(_S_round_up(__n)); else { *__my_free_list = __result -> _M_free_list_link;//调整free-list __ret = __result; } } return __ret; };
四、空间释放函数
第二级配置器的接口函数。注意作用是回收区块,大于128字节调用第一级配置器,小于128字节用free-list回收。
/* __p may not be 0 */ static void deallocate(void* __p, size_t __n) { if (__n > (size_t) _MAX_BYTES) malloc_alloc::deallocate(__p, __n);//大于128字节调用第一级配置器 else { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n);//找出对于位置 _Obj* __q = (_Obj*)__p; __q -> _M_free_list_link = *__my_free_list;//回收区块 *__my_free_list = __q; } }
五、重新填充空间
template <bool __threads, int __inst>void*__default_alloc_template<__threads, __inst>::_S_refill(size_t __n){ int __nobjs = 20; char* __chunk = _S_chunk_alloc(__n, __nobjs);//获取nobjs个区块作为free-lisr的新节点 _Obj* __STL_VOLATILE* __my_free_list; _Obj* __result; _Obj* __current_obj; _Obj* __next_obj; int __i; if (1 == __nobjs) return(__chunk);//如果只获取了一个区块直接返回给调用者 __my_free_list = _S_free_list + _S_freelist_index(__n);//否则加入到free-list中 /*在chunk空间内建立free-list */ __result = (_Obj*)__chunk; *__my_free_list = __next_obj = (_Obj*)(__chunk + __n); for (__i = 1; ; __i++) {//将free-list各个节点串接起来 __current_obj = __next_obj; __next_obj = (_Obj*)((char*)__next_obj + __n); if (__nobjs - 1 == __i) { __current_obj -> _M_free_list_link = 0; break; } else { __current_obj -> _M_free_list_link = __next_obj; } } return(__result);}
六、内存池
template <bool __threads, int __inst>char*__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, int& __nobjs){ char* __result; size_t __total_bytes = __size * __nobjs;//内存需求量 size_t __bytes_left = _S_end_free - _S_start_free;//内存池的剩余空间 if (__bytes_left >= __total_bytes) {//剩余空间满足需求量 __result = _S_start_free; _S_start_free += __total_bytes; return(__result); } else if (__bytes_left >= __size) {//剩余不满足需求量,但满足一个以上的区块 __nobjs = (int)(__bytes_left/__size); __total_bytes = __size * __nobjs; __result = _S_start_free; _S_start_free += __total_bytes; return(__result); } else {//完全不能提供 size_t __bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size >> 4); // 试图使用残余区块 if (__bytes_left > 0) { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__bytes_left); //调整free—list使参与区块能够加入 ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list; *__my_free_list = (_Obj*)_S_start_free; } _S_start_free = (char*)malloc(__bytes_to_get);//配置堆空间,用来补充内存池 if (0 == _S_start_free) {//申请失败 size_t __i; _Obj* __STL_VOLATILE* __my_free_list; _Obj* __p; // 搜索free-list中可用区块 for (__i = __size; __i <= (size_t) _MAX_BYTES; __i += (size_t) _ALIGN) { __my_free_list = _S_free_list + _S_freelist_index(__i); __p = *__my_free_list; if (0 != __p) {//有可用区块 *__my_free_list = __p -> _M_free_list_link; _S_start_free = (char*)__p; _S_end_free = _S_start_free + __i; return(_S_chunk_alloc(__size, __nobjs)); // 任何残余区块都已编入到free-liat中 } } _S_end_free = 0;// 防止出现意外(内存不足) _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);//调用第一级配置器 } _S_heap_size += __bytes_to_get; _S_end_free = _S_start_free + __bytes_to_get; return(_S_chunk_alloc(__size, __nobjs)); }}
0 0
- STL源码剖析之空间配置器Allocator
- SGI STL 空间配置器(allocator)源码剖析
- SGI STL 空间配置器(allocator)源码剖析
- STL源码剖析 — 空间配置器(allocator)
- STL源码学习之空间配置器allocator【2013.11.15】
- STL源码剖析之空间配置器
- STL源码剖析之空间配置器
- STL源码剖析之空间配置器
- stl源码剖析之空间配置器
- STL之空间配置器allocator
- stl之空间配置器Allocator
- 《STL源码剖析》读书笔记--第二章 空间配置器(allocator)
- STL中的空间配置器allocator的实现原理及源码剖析
- STL源码剖析之一:空间适配器(allocator)
- 《STL源码剖析》之配置自己简单的allocator
- STL:allocator空间配置器
- stl源码剖析读书笔记之allocator
- 《STL源码剖析》STL空间配置器
- java socket参数详解:BackLog
- GPU&CUDA几个基本概念
- C++如何求一个十进制数转化为二进制数之后1的个数
- Android_6.0 ROM编译(Kernel + Android)ERROR总结 + 解决方案
- 移植Linux内核自带LCD驱动程序到JZ2440开发板
- STL源码剖析之空间配置器Allocator
- Android 四大组件 Service 服务
- Android六大网络框架
- ndk platform-19风水岭
- TraceView性能优化工具使用
- 精选动画片大全-儿童益智学习屋
- Elasticsearch映射(mapping)与分析(analysis)
- Vue.js自定义指令的用法与实例
- hdu 2222AC自动机模板题