STL初探——第二级配置器 __default_alloc_template的学习心得

  SGI STL 第二级配置器使用的是memory pool,即内存池,相比较于第一级空间配置器,第二级空间配置器多了许多限制,主要是为了防止申请小额区块过多而造成内存碎片。当然小额区块在配置时实际上是对空间配置器效率的一种伤害。另外,索求任何一块内存,都得需要一些额外内存来进行标记,虽然这些标记占内存很小很小,但蚂蚁多咬死象,小区块多了,这些小标记还是挺浪费内存的,但这也无法避免,毕竟系统需要靠这些小标记管理内存。

  SGI 第二级配置器的做法是,如果区块足够大,超过128bytes时,就移交第一级配置器处理。当区块小于128bytes时,则以内存池的方式管理,第二级配置器也叫做次层配置器:每次配置一大块内存,并维护对应的自由链表:free-list。为了方便管理,SGI STL 第二级配置器会主动为小额区块的需求量的大小上调至 8 的倍数,并维护16个 free-list,依次为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,free-list节点结构如下:

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

  _Obj 用的是 union,_M_free_list_link,是一个指针,指向下一个 _Obj,_M_client_data 也可以当做一个指针,指向实际区块,这样做的好处是不会为了维护链表所必须的指针而造成内存的另一种浪费。

  

  

template <bool threads, int inst>
class __default_alloc_template {

private:

//区块上调枚举
#if ! (defined(__SUNPRO_CC) || defined(__GNUC__))
    enum {_ALIGN = 8};
    enum {_MAX_BYTES = 128};
    enum {_NFREELISTS = 16}; // _MAX_BYTES/_ALIGN
# endif

//区块上调函数
  static size_t
  _S_round_up(size_t __bytes) 
    { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }

__PRIVATE:
//链表节点联合体
  union _Obj {
        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[]; 
# else
    //16个 free-list
    static _Obj* __STL_VOLATILE _S_free_list[_NFREELISTS]; 
# endif
  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:
  /* __n must be > 0      */
  static void* allocate(size_t __n)
  {
    ...
  };

  /* __p may not be 0 */
  static void deallocate(void* __p, size_t __n)
  {
    ...
  }

  static void* reallocate(void* __p, size_t __old_sz, size_t __new_sz);

};

//这四个函数是静态数据成员的定义与初始设定
//__threads是线程设定,咱们不管,__inst完全没用到。。。
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, };
};
既然选择了远方,便只顾风雨兼程
原文地址:https://www.cnblogs.com/Forever-Road/p/6809640.html