STL(六)之空间配置器

SGI STL内存管理

在SGI STL版本的内存管理中,使用这样一种方式来分配内存:内存分配+对象初始化。首先是分配内存,其次是根据对象的类型(是否为POD【Plain of Data】)来使用最有效的方式来初始化对象。回收内存也是用同样的方式:析构对象+回收内存,根据对象是否为POD类型,确定最有效的析构方式。
SGI STL使用双层级配置器,第一级配置器直接使用malloc()和free(),第二级根据如下策略:当配置区块>128 Bytes时,视之为“足够大”,调用一级配置器,否则视之为过小,调用二级配置器。

一级配置器:__malloc_alloc_template

template <int __inst>        //非型别参数,没排上用处
class __malloc_alloc_template { private: static void* _S_oom_malloc(size_t); //用来处理内存不足的情况,out of memory static void* _S_oom_realloc(void*, size_t); static void (* __malloc_alloc_oom_handler)(); public: static void* allocate(size_t __n) //分配内存 { void* __result = malloc(__n); if (0 == __result) __result = _S_oom_malloc(__n); return __result; } static void deallocate(void* __p, size_t ) //释放内存 {free(__p);} static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz) //在原有的基础上再次分配内存 { void* __result = realloc(__p, __new_sz); if(0 == __result) __result = _S_oom_realloc(__p, __new_sz); return __result; } static void (* __set_malloc_handler(void (*__f)()))() //指定自己的oom handler { void (* __old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = __f; return(__old); } }; template <int __inst> void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0; //默认没有oom处理 template <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); } }

二级配置器:__default_alloc_template

template <bool threads, int inst>
class __default_alloc_template { private: enum {_ALIGN = 8}; //每个小内存块的大小相差为8 enum {_MAX_BYTES = 128}; //最大的小内存的大小为128bytes enum {_NFREELISTS = 16}; //小内存块的类型 static size_t _S_round_up(size_t __bytes) //将需要的小内存块大小上调为8的倍数 { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); } //(x+7)& ~7 union _Obj //在区块中保存的对象类型,为了节省内存,使用这种方式 { union _Obj* _M_free_list_link; char _M_client_data[1]; }; private: static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; //存储对象链表 static size_t _S_freelist_index(size_t __bytes) //根据需要分配的对象,获取区块索引 {return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);} static void* _S_refill(size_t __n); 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; public: static void* allocate(size_t __n) //获取内存块 { void* __ret = 0; if (__n > (size_t) _MAX_BYTES) //如果需要的内存块大小>128,调用一级配置器进行分配 return __ret = malloc_alloc::allocate(__n); _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n); //获取需要的free_list _Obj* __RESTRICT __result = *__my_free_list; //从链表头部获取一块小内存 if (__result == 0) //如果没有找到可用的free_list,准备重新填充free list { __ret = _S_refill(_S_round_up(__n)); return __ret; } *__my_free_list = __result -> _M_free_list_link; //调整free_list的头部指向下一个 return __result; }; static void deallocate(void* __p, size_t __n) //释放一块小的区块至free_list { if (__n > (size_t) _MAX_BYTES) //如果想要归还的区块>128,调用一级配置器 malloc_alloc::deallocate(__p, __n); else { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__n); //找到合适的free_list _Obj* __q = (_Obj*)__p; //临时存储即将归还的小区快 __q -> _M_free_list_link = *__my_free_list; //将这个归还的小区块置为free_list的头部 *__my_free_list = __q; //调整区块列表的头部指针 } } static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz); } ; template <bool __threads, int __inst> void* __default_alloc_template<__threads, __inst>::_S_refill(size_t __n) //为内存不足的free_list重新填充空间 { int __nobjs = 20; char* __chunk = _S_chunk_alloc(__n, __nobjs); //尝试调用chunk_alloc获取20个新的区块作为free_list的新节点 _Obj* __STL_VOLATILE* __my_free_list; _Obj* __result; _Obj* __current_obj; _Obj* __next_obj; int __i; if (1 == __nobjs) //如果获取的区块数量为1,这块可以直接返回,等下次内存不足时在做处理 return(__chunk); __my_free_list = _S_free_list + _S_freelist_index(__n); //在链表中获取合适的free_list __result = (_Obj*)__chunk; //从刚刚获取的20个区块中,先拿走一个,作为返回的结果 *__my_free_list = __next_obj = (_Obj*)(__chunk + __n); //将第二个区块作为头部,然后通过循环,将这些区块添加到free_list中 for (__i = 1; ; __i++) { __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) //从内存池中获取足够的内存给free_list使用 { 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) //如果内存池中还有零头,将零头加入free_list中 { _Obj* __STL_VOLATILE* __my_free_list = _S_free_list + _S_freelist_index(__bytes_left); ((_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); //配置heap空间,用来补充内存池 if (0 == _S_start_free) //如果从堆中获取内存失败,我们将采用如下策略:检验我们手上空闲的,较大的内存块,将这个较大的内存块归还到堆中,然后就可以重新进行配置了 { size_t __i; _Obj* __STL_VOLATILE* __my_free_list; _Obj* __p; for (__i = __size;__i <= (size_t) _MAX_BYTES;__i += (size_t) _ALIGN) { __my_free_list = _S_free_list + _S_freelist_index(__i); //获取当前的free_list __p = *__my_free_list; //如果这个free_list的head存在 if (0 != __p) { *__my_free_list = __p -> _M_free_list_link; _S_start_free = (char*)__p; //将这个头部的free_list归还到堆中去,调整堆指针的位置 _S_end_free = _S_start_free + __i; return(_S_chunk_alloc(__size, __nobjs)); //不用担心有剩余,任何残余的零头都会被编入合适的free_list中去 } } _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)); } } template <bool __threads, int __inst> char* __default_alloc_template<__threads, __inst>::_S_start_free = 0; template <bool __threads, int __inst> char* __default_alloc_template<__threads, __inst>::_S_end_free = 0; template <bool __threads, int __inst> size_t __default_alloc_template<__threads, __inst>::_S_heap_size = 0; template <bool __threads, int __inst> typename __default_alloc_template<__threads, __inst>::_Obj* __STL_VOLATILE __default_alloc_template<__threads, __inst> ::_S_free_list[ # if defined(__SUNPRO_CC) || defined(__GNUC__) || defined(__HP_aCC) _NFREELISTS # else __default_alloc_template<__threads, __inst>::_NFREELISTS # endif ] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };

标准配置器:simple_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)); } };

基本的内存配置工具

其中最影响效率的因素在于判断是Value否为POD类型,根据是否为POD类型做出不同的处理。

uninitialized_copy

template <class _InputIter, class _ForwardIter> inline _ForwardIter uninitialized_copy(_InputIter __first, _InputIter __last, _ForwardIter __result) { return __uninitialized_copy(__first, __last, __result, __VALUE_TYPE(__result)); //萃取出__result的类型,判断是否为POD类型 } inline char* uninitialized_copy(const char* __first, const char* __last, char* __result) //随之后是两个特化的版本 { memmove(__result, __first, __last - __first); return __result + (__last - __first); } inline wchar_t* uninitialized_copy(const wchar_t* __first, const wchar_t* __last, wchar_t* __result) { memmove(__result, __first, sizeof(wchar_t) * (__last - __first)); return __result + (__last - __first); } 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; //萃取_Tp的类型 return __uninitialized_copy_aux(__first, __last, __result, _Is_POD()); //利用重载的方式在编译期选择处理 } template <class _InputIter, class _ForwardIter> inline _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,_ForwardIter __result, __true_type) { return copy(__first, __last, __result); //如果是POD类型,直接进行memcpy进行处理就行 } template <class _InputIter, class _ForwardIter> _ForwardIter __uninitialized_copy_aux(_InputIter __first, _InputIter __last,_ForwardIter __result,__false_type) { _ForwardIter __cur = __result; //如果非POD类型,逐个在_result类型上进行construct __STL_TRY { for ( ; __first != __last; ++__first, ++__cur) _Construct(&*__cur, *__first); return __cur; } __STL_UNWIND(_Destroy(__result, __cur)); }

uninitialized_copy_n

template <class _InputIter, class _Size, class _ForwardIter> inline pair<_InputIter, _ForwardIter> uninitialized_copy_n(_InputIter __first, _Size __count,_ForwardIter __result) { return __uninitialized_copy_n(__first, __count, __result,__ITERATOR_CATEGORY(__first)); } template <class _InputIter, class _Size, class _ForwardIter> inline pair<_InputIter, _ForwardIter> __uninitialized_copy_n(_InputIter __first, _Size __count,_ForwardIter __result) { return __uninitialized_copy_n(__first, __count, __result,__ITERATOR_CATEGORY(__first)); } template <class _RandomAccessIter, class _Size, class _ForwardIter> inline pair<_RandomAccessIter, _ForwardIter> __uninitialized_copy_n(_RandomAccessIter __first, _Size __count,_ForwardIter __result,random_access_iterator_tag) { _RandomAccessIter __last = __first + __count; return pair<_RandomAccessIter, _ForwardIter>(__last,uninitialized_copy(__first, __last, __result)); } template <class _InputIter, class _Size, class _ForwardIter> pair<_InputIter, _ForwardIter> __uninitialized_copy_n(_InputIter __first, _Size __count,_ForwardIter __result,input_iterator_tag) { _ForwardIter __cur = __result; __STL_TRY { for ( ; __count > 0 ; --__count, ++__first, ++__cur) _Construct(&*__cur, *__first); return pair<_InputIter, _ForwardIter>(__first, __cur); } __STL_UNWIND(_Destroy(__result, __cur)); }

uninitialized_fill

template <class _ForwardIter, class _Tp>
inline void uninitialized_fill(_ForwardIter __first,_ForwardIter __last, const _Tp& __x) { __uninitialized_fill(__first, __last, __x, __VALUE_TYPE(__first)); } 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> 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> inline void __uninitialized_fill_aux(_ForwardIter __first, _ForwardIter __last,const _Tp& __x, __true_type) { fill(__first, __last, __x); }

uninitialized_fill_n

template <class _ForwardIter, class _Size, class _Tp>
inline _ForwardIter uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x) { return __uninitialized_fill_n(__first, __n, __x, __VALUE_TYPE(__first)); } template <class _ForwardIter, class _Size, class _Tp, class _Tp1> inline _ForwardIter __uninitialized_fill_n(_ForwardIter __first, _Size __n, const _Tp& __x, _Tp1*) { typedef typename __type_traits<_Tp1>::is_POD_type _Is_POD; return __uninitialized_fill_n_aux(__first, __n, __x, _Is_POD()); } template <class _ForwardIter, class _Size, class _Tp> _ForwardIter __uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,const _Tp& __x, __false_type) { _ForwardIter __cur = __first; __STL_TRY { for ( ; __n > 0; --__n, ++__cur) _Construct(&*__cur, __x); return __cur; } __STL_UNWIND(_Destroy(__first, __cur)); } template <class _ForwardIter, class _Size, class _Tp> inline _ForwardIter __uninitialized_fill_n_aux(_ForwardIter __first, _Size __n,const _Tp& __x, __true_type) { return fill_n(__first, __n, __x); }
 

转载于:https://www.cnblogs.com/xcb-1024day/p/11332488.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值