SGI-STL简记(一)-内存分配器解析

defalloc.h :
    默认分配器allocator:
        早期专用于HP的默认分配器,目前是不被赞成使用的;
        仅提供了allocator模板简单封装,重声明(或类型外抛)一些必要的类型Type,此外提供申请和释放内存接口(底层直接使用全局::operator new和::operator delete进行内存分配和释放);
        取引用的地址、取常引用的常量地址等接口;
        allocate:内部取消new申请内存时失败跳转处理函数而是直接抛出异常;
        init_page_size:申请页大小下最大空间大小,采用4K(4096)/sizeof(T)计算;
        max_size:申请最大空间大小,采用UINT_MAX/sizeof(T)计算。
        此外模板特化allocator<void>,仅重声明指针类型;
        
stl_alloc.h:
    STL内部的分配器allocator(默认的__default_alloc_template模板类采用线程安全的分配器):
        同默认分配器重声明了一些必要的类型Type、申请和释放内存接口、取引用的地址、取常引用的常量地址、max_size:申请最大空间大小,采用size_t(-1)/sizeof(T)计算;
        不同点在于其底层内存处理使用的是一个alloc(实际为__default_alloc_template模板类或malloc_alloc(__malloc_alloc_template)),通过它进行申请和释放内存;
        提供了默认构造、析构、赋值构造、构造construct(通过"放置"new)、销毁destroy(通过调用其析构函数)、提供rebind类结构声明;
        此外模板特化allocator<void>,重声明了一些必要的类型Type;
    STL内部的分配适配器__allocator(通过模板参数提供底层内存分配):
        同上者一样,不过底层内存处理为一个模板参数提供的类型对象__underlying_alloc;当__allocator<_Tp, alloc>时则与allocator<_Tp>相同;
    底层内存处理模板类__default_alloc_template(可认为其为一个内存池的模板类):
        模板参数分别为bool threads, int inst,threads为true则为线程安全,否则只能用于单线程情况;inst只是一个标识,用以支持多个不同的__default_alloc_template实例;
        _ALIGN:字节对齐8字节;
        _MAX_BYTES:最大字节128字节,超过则调用malloc_alloc分配;
        _NFREELISTS:释放后的指针列表_S_free_list大小128/8=16;
        _S_free_list:释放后列表数组,保存着指向各索引空间链表地址的指针;
        _S_start_free(0)、_S_end_free(0)、_S_heap_size(0):块分配状态;
        _S_node_allocator_lock:分配器锁对象;
        内部自动锁类_Lock;用于包装_S_node_allocator_lock加解锁,windows下使用的是原子锁,其他平台下使用的是引用计数加pthread_mutex_lock;
        _Obj:联合类,封装链表指针或链表下一个对象,为了节省空间把申请到的空间作为指向下一个节点内存;
        供外部调用接口allocate分配内存,deallocate释放内存,reallocate重新申请内存;
        _S_round_up:字节对齐,调整到_ALIGN字节的整数倍(n + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1));
        _S_freelist_index:计算当前申请字节大小在_S_free_list列表中的位置索引(n + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1,范围0~15;
        故得出_S_free_list保存的链表申请布局如:[8, 16, 24, 32, 40, 48, 56, 64,..., 128],每个节点链表为单链表,最新的节点申请和释放均为表头,
        这样可加速申请和释放操作,事实上释放的节点直接加载节点链表的表头并不free,若链表为空则申请相应索引下大小的空间内存;
        _S_refill、_S_chunk_alloc:填充节点链表以及申请空间内存(事实上_S_chunk_alloc内部在开始申请空间时并不是申请相应空间大小,而是对应申请索引布局下
        字节的更多倍(为了再次避免内存碎片和频繁申请)(具体操作细节可以看一下源码实现),_S_refill负责填充_S_chunk_alloc申请后未被使用的链表申请布局拆分至相应
        的节点链表上供下一次直接供给申请使用而无需再申请内存,而后返回一片内存供上层使用);
    __default_alloc_template模板类内部用到的malloc_alloc大块内存分配类(即__malloc_alloc_template<0>模板类):
        __malloc_alloc_template提供对外使用接口:
            allocate:内部调用malloc申请内存,若失败,则调用_S_oom_malloc;
            deallocate:内部直接调用free释放内存;
            reallocate:内部调用realloc重申请内存,若失败,则调用_S_oom_realloc;
            此外还提供了__set_malloc_handler设置申请处理函数;
            _S_oom_malloc:内部通过判断申请处理函数是否为空,若为空则抛出bad_alloc异常,否则执行处理函数并继续循环调用malloc直到申请成功;每次申请前均会
            调用该处理函数;
            _S_oom_realloc:同_S_oom_malloc类型,循环调用realloc重申请;
            
    依赖关系:分配器__allocator、allocator->分配器模板__default_alloc_template(核心组件)->__malloc_alloc_template(大块内存申请处理)(或全局malloc、free)->
              全局malloc、free;
              
    __allocator、allocator、__default_alloc_template具备申请管理大、小内存机制(最底层是通过调用malloc/free/remalloc实现)以及锁资源保护(当然也可以用宏设置不加锁,
    此时若上层需要自己维护自己的资源,是否给你的某些资源加锁保护,依赖于具体情况),其他直接调用malloc/free/remalloc实现;
            
    其他的内存分配适配器模板类:
        simple_alloc简易封装分配器、debug_alloc分配内存前带额外8字节的调试信息封装分配器、_Alloc_traits分配器类型萃取模板类;
        其中_Alloc_traits模板参数的分配器可为特化版本类型,如:allocator、__allocator、__malloc_alloc_template、__default_alloc_template、debug_alloc;
        此外_Alloc_traits模板参数的分配器的_S_instanceless为以上类型时值为true,其他用户自定义类型则为false,当为true时通过rebind获取allocator_type,
        其他则通过相应分配器获取allocator_type,此外还提供了simple_alloc简易封装分配器的_Alloc_type类型;
        _Alloc_traits用在容器模板类的各个角落,并且默认情况下容器的分配器为allocator<T>或alloc(__default_alloc_template或malloc_alloc(__malloc_alloc_template));
        single_client_alloc为__default_alloc_template不加锁时的分配器很快但不安全,malloc_alloc安全但是不够快,allocator为默认的分配器安全比较高效;
    

猜你喜欢

转载自www.cnblogs.com/haomiao/p/11647200.html
今日推荐