STL《空间配置器(allocators)》

STL_空间配置器(allocators)

SGI STL中的两级空间分配器

第一级 __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); 

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
  static void (* __malloc_alloc_oom_handler)(); 
#endif

public:

  static void* allocate(size_t __n)
  {
    void* __result = malloc(__n); /*直接调用malloc()*/  
    if (0 == __result) __result = _S_oom_malloc(__n); /*处理OOM方式都相似,只列出allocate情况*/
    return __result;
  }

  static void deallocate(void* __p, size_t /* __n */)
  {
    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;
  }                       
  // 仿set_new_handler(只用于::operator new配置内存方式,malloc不能使用)
  // typedef void(*pf)() PF
  // PF __set_malloc_handler(void (*__f)())
  // __set_malloc_handler接收 void(*)()函数指针
  // 同时返回 void(*)()函数指针

  static void (* __set_malloc_handler(void (*__f)()))()
  {
    void (* __old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = __f;
    return(__old);        
  }

};


#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int __inst>
void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0; /*初始化位空,需要用户指定*/
#endif

template <int __inst>
void* __malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)
{
    void (* __my_malloc_handler)();
    void* __result;

    for (;;) { /*使用设定的handler处理,重复申请*/
        __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);/*如果成功则返回*/
    }
}

第一级非常简单,只是把malloc,free,realloc包装了一下,并提供一个类似set_new_handler的方法。用户需要自己设定handler,否则使用默认的throw std::bad_alloc()方式。

第二级 __default_alloc_template

第二级主要避免小额区块造成的内存碎片,以及频繁申请带来的负担。SGI的二级做法是如果区块大于128字节,移交第一级,否则以内存池管理,每次申请一块大内存,通过空闲链表(free-lists)分配和回收内存,二级配置会将小额区块的请求调到8的倍数。并维护16个free-lists各自管理大小为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128的区块。

union _Obj {
    union _Obj* _M_free_list_link;
    char _M_client_data[1];    /*The client sees this.*/
};

使用union结构体_Obj,第一个字段可视为指针,指向同一个free-list的下一个块,在freelist中用作链表;第二个字段可视为指向这一区块的指针,当申请到这一块内存后,p = *_Obj指向可用的内存。

enum {_ALIGN = 8};
enum {_MAX_BYTES = 128};
enum {_NFREELISTS = 16};

static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; //16个freelist

static size_t _S_round_up(size_t __bytes) {//将 size 上调为8的倍数
    return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1));
}

static  size_t _S_freelist_index(size_t __bytes) { // 返回size对应的freelist下标
      return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1);
}
/*allocate -- 用户分配空间*/
/* __n must be > 0 */
  static void* allocate(size_t __n)
  {
    void* __ret = 0;

    if (__n > (size_t) _MAX_BYTES) { //大于128,调用第一级
      __ret = malloc_alloc::allocate(__n);
    }
    else {
      _Obj* __STL_VOLATILE* __my_free_list
          = _S_free_list + _S_freelist_index(__n);//得到对应freelist下标
// Acquire the lock here with a constructor call.
// This ensures that it is released in exit or during stack
// unwinding.
#ifndef _NOTHREADS
/*REFERENCED*/
      _Lock __lock_instance; //多线程相关
#endif
      _Obj* __RESTRICT __result = *__my_free_list;
      if (__result == 0)//初次初始化||空间无剩余 
        __ret = _S_refill(_S_round_up(__n));//重新申请
      else {
        *__my_free_list = __result -> _M_free_list_link;//更新freelist列表,最后一块的_M_free_list_link设为0
        __ret = __result;//返回内存地址
      }
    }

    return __ret;
  };
/*_S_refill --  填充freelist*/
template <bool __threads, int __inst>
void*
__default_alloc_template<__threads, __inst>::_S_refill(size_t __n)
{
    int __nobjs = 20; //分配__nobjs个区块
    char* __chunk = _S_chunk_alloc(__n, __nobjs);//__nobjs 为value-result参数  
    _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);

/* 使用剩余内存构建该下标的freelist */
      __result = (_Obj*)__chunk;
      *__my_free_list = __next_obj = (_Obj*)(__chunk + __n);
      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;//最后一块设为0
            break;
        } else {
            __current_obj -> _M_free_list_link = __next_obj;
        }
      }
    return(__result);
}
/*_S_chunk_alloc -- 从内存池取一定数量区块*/
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) {//足够分配__nobjs个区块
        __result = _S_start_free;
        _S_start_free += __total_bytes;//分配好后,剩余的留给内存池,用作下次分配
        return(__result);
    } else if (__bytes_left >= __size) {//不够__nobjs块,剩下的全都分配来,更新__nobjs
        __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);//申请两倍 + heap_size/16
        // 试试剩下的(必定为8的倍数)够不够小尺寸freelist使用
        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);
        if (0 == _S_start_free) {//malloc()失败,不会尝试小于__bytes_to_get的请求,出于效率以及减少内存碎片
            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);
                __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));//重新分配调整,修正__nobjs
                }
            }
            _S_end_free = 0;    // 无论如何申请不到,调用第一级,试试OOM handler有没有用
            _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));//修正__nobjs,将多余内存归还内存池
    }
}
/*deallocate() -- 用户释放空间*/
static void deallocate(void* __p, size_t __n)
{
  if (__n > (size_t) _MAX_BYTES) 
    malloc_alloc::deallocate(__p, __n);调用第一级
  else {
    _Obj* __STL_VOLATILE*  __my_free_list = _S_free_list + _S_freelist_index(__n);
    _Obj* __q = (_Obj*)__p;

    // acquire lock
#ifndef _NOTHREADS
    /*REFERENCED*/
    _Lock __lock_instance;
#endif /* _NOTHREADS */
    __q -> _M_free_list_link = *__my_free_list;
    *__my_free_list = __q;//将 __q区间插入对应freelist头部
    // lock is released here
   }
 }
/*reallocate -- 重新分配空间*/
template <bool threads, int inst>
void*
__default_alloc_template<threads, inst>::reallocate(void* __p,
                                                    size_t __old_sz,
                                                    size_t __new_sz)
{   
    void* __result;
    size_t __copy_sz;

    if (__old_sz > (size_t) _MAX_BYTES && __new_sz > (size_t) _MAX_BYTES) {
        return(realloc(__p, __new_sz));//调用第一级
    }
    if (_S_round_up(__old_sz) == _S_round_up(__new_sz)) return(__p);
    __result = allocate(__new_sz);//申请
    __copy_sz = __new_sz > __old_sz? __old_sz : __new_sz;
    memcpy(__result, __p, __copy_sz);//拷贝
    deallocate(__p, __old_sz);//释放
    return(__result);
}

空间初始化
内存分配完毕后,STL定义五个全局函数用于未初始化的空间。

construct && destroy() – 用于构造,析构对象

#include <new.h> //使用placement new

template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
  new ((void*) __p) _T1(__value);// T1::T1(__value)
}  

template <class _T1>      
inline void _Construct(_T1* __p) {
  new ((void*) __p) _T1();
}

template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
  __pointer->~_Tp();
}
//接收迭代器,找出元素类别,根据__type_traits<>采取适当措施
template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
  __destroy(__first, __last, __VALUE_TYPE(__first));
}
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)//non-trivial destructor
{
  for ( ; __first != __last; ++__first)
    destroy(&*__first);
}

template <class _ForwardIterator>
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}//trivial destructor,不采取操作
construct()通过指针p,可选的初值value,使用placement new运算子在对象构造在p所指的空间上。
destroy()有两个版本,第一个接受一个指针;第二个接收迭代器,将[first,last)范围内的所有对象析构,首先使用 value_type获得对象类型,在进行trivial destructor的判定,如果析构函数是不重要的,destroy()最终不调用任何操作,否则才调用析构函数。
uninitialized_fill_n, uninitialized_fill, unitialized_copy

/*__uninitialized_fill_n : first:初始化空间起始,n:空间大小,x:初值*/
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());
}
/*判断Tp1是否为POD(plain old data)类型,简单来说POD类型支持memcpy等类似的函数直接拷贝对象的二进制值。*/
//是POD类型,fill_n通过赋值进行填充
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);
}
// 非POD,调用Construct。
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));//一旦发生异常全部析构
}
这三个函数都要求"commit or rollback"语义,要么产生所有元素,要么不产生任何元素。上面异常处理模块保证了这一语义。
/*uninitlized_cpoy,first:起始位置,last:结束位置,result:初始化空间起始*/
template <class _InputIter, class _ForwardIter>
inline _ForwardIter 
uninitialized_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());
}
//POD类型,调用copy,填充赋值
template <class _InputIter, class _ForwardIter>
inline _ForwardIter 
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
                         _ForwardIter __result,         
                         __true_type)                   
{  
  return copy(__first, __last, __result);
}
//非POD类型
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));
} 

对于char* 和 wchar_t*两种类型,uninitialized_copy直接采用memmove直接移动内容

//uninitialized_copy: first:初始化空间起始,last:初始化空间结束(前闭后开),x:初值
 template <class _InputIter, class _ForwardIter>
 inline _ForwardIter
 uninitialized_copy(_InputIter __first,
                    _InputIter __last,
                    _ForwardIter __result)
 {
   return __uninitialized_copy(__first, __last, __result,
                               __VALUE_TYPE(__result));
 }

//POD类型

template <class _ForwardIter, class _Tp>
inline void
__uninitialized_fill_aux(_ForwardIter __first,
                         _ForwardIter __last,
                         const _Tp& __x,
                         __true_type)
{
  fill(__first, __last, __x);
}

//非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));
}

三个函数实现了不同的功能,它们都用于未初始化的空间。

http://blog.csdn.net/wuyang8/article/details/53894021

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值