SGI-STL简记-内存分配器解析
Posted haomiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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为默认的分配器安全比较高效;
以上是关于SGI-STL简记-内存分配器解析的主要内容,如果未能解决你的问题,请参考以下文章