空间配置器存在的原因:
①频繁的申请和释放空间,就会频繁地调用malloc和free函数,函数调用时栈帧的开辟和回退,这些都是有开销的,就会降低运行的效率。
②频繁的申请和和释放空间,会造成内存碎片的问题。使得即使有足够的空间,也申请不到一个连续的空间。
SGI 标准的空间配置器:std::allocator, 它符合部分标准,但效率不佳,它只是把以下两个函数::operator new(只分配内存)和::operator delete(只回收内存)做了一层薄薄的包装而已(一般不使用)。
SGI 特殊的空间配置器:std::alloc 配置器定义在<memory>之中,SGI<memory>内包含两个文件:
1、#include<stl_alloc.h> 定义了一、二级配置器,负责内存空间的内配和释放,配置其名为alloc。
一级配置器:template<int inst>
class _malloc_alloc_template{…};
其中:①allocate()直接使用malloc();deallocate()直接使用free()。
②模拟C++的set_new_hander()以处理内存不足的情况。
二级配置器:template<bool threads,int inst>
class _default_alloc_template{…};
其中:①维护16个自由链表(free lists),负责维护16种小型区块的次配置能力。
内存池(memory poll)以malloc()配置而得。
如果内存不足,转调用第一级配置器(那儿有处理程序)。
②如果需求区块大于128bytes,就调用一级配置器。需求区块小于128bytes时,采用内存池整理方式,不再求助于一级配置器。
对于是只开放一级配置器,还是同时开放二级配置器,取决于_USE_MALLOC是否被定义(如果定义:一级配置器;否则:二级配置器)
在这两个配置器之上还有一层包装:simple_alloc ,使alloc具备标准接口。
SGI STL 容器的定义中默认使用二级空间配置器。
整个空间配置过程以一个例子说明:
当vector需要扩容时,有三个步骤:1.重新配置空间,2.将原空间数据复制到新分配的空间,3. 释放原空间
在第一步重新配置空间中,就需要通过空间配置器去进行空间分配。
具体:
1、需配置空间大小n大于128字节,调用一级配置器进行分配。
2、需配置大小n小于128字节:
(1)在二级配置器维护的16个链表(free_list)中找到对接近n且大于n的区块链表,从这个区块中拔出首区块分配出去。
(2)如果free_list中没有合适区块了,则从内存池中分配空间给free_list(默认为20*k)
(3)如果内存池中也没有空间了,则从heap中malloc所需区块大小(以(2)中的默认大小为准)的2倍+附加量给内存池,在递归调用自己重新给free_list分配
(4)如果malloc失败,则从free_list上未使用且足够大的区块中找一块去配置所需区块,再去给用户分配空间
(5)如果free_list中也没有未使用的区块了,则调用一级配置器。因为以及配置器有out_of_memory机制,可以去处理分配失败问题,有机会释放其他的内存拿来此处用,如果失败,发出bad_alloc异常。
2、#include<stl_construct.h> 定义了construct() 和destroy(),都是全局函数,负责对象的构造和析构。