前几天面试到问STL中的空间配置策略,当时支支吾吾没说全,回来翻出好久没看的JJHou的《STL源码剖析》,细细品读了第二章,对其做如下总结,一来考验下自己的STL功底,二来希望对广大对于STL内存配置迷糊的同学们有帮助。这里主要说SGI STL,并非标准
STL有6大组件:容器container,算法algorithm,迭代器iterator,空间配置器allocator,仿函数function和适配器adaper. 其中空间配置器有simple_allocator和alloc两个,simple_allocator只是在::operator new和::operator delete上做了薄薄的包装。STL有它特殊的空间配置器alloc,它有二级配置能力。STL的空间配置主要包括2部分,(1)分配空间;(2)调用ctor进行构造;
首先来说说比较简单的构造模板,它在STL的头文件stl_construct.h中描述。主要包含construct和destroy两个全局函数。在construct()函数中传入地址和const对象值,采用placement new技术构造,并初始化。destroy()相对复杂一点,利用__type_traits对iterator的相应型别做判断,如果是平凡类型(POD型别),则不做任何工作,只有是非平凡类型时才迭代析构,并衍生char*和wchar_t*的特化版本,这一切都是为了提高效率。
下面讨论alloc的空间申请,这包含于stl_alloc.h中。它分为两级配置器,当需要分配的空间大小大于128bytes时调用第一级分配,直接调用malloc,realloc和free等C函数,并封装为malloc_alloc模板,并实现类似于set_new_handler的set_malloc_handler的oom(out of memory)处理句柄。此为第一级配置器
第二级配置器是针对申请的空间小于128bytes的情况而设计的,叫__default_alloc_template。以8为步进,分别采用空闲列表和内存池保存可分配的空间,期间涉及的不同操作主要是在空闲列表相应大小的内存用完的情况下,那么refille(size_t n)函数调用chunk_alloc(size_t size,int nobjs)来为空闲列表插入新的可用空间。chunk_alloc函数首先检查内存池是否有足够的空间,有则分配,没有清理池中剩余的内存到空闲列表中,然后往系统堆申请空间(malloc),若申请失败,则查找空闲列表中更大的空间来填补没有内存的项;这些都不行那么只能调用用户可能设置了的配置失败处理函数(通过set_malloc_handler配置),期望通过系统内存的回收来成功获得内存。
用到的技术主要有:版本特化,模板参数推倒机制,placement new等