STL源码剖析学习二:空间配置器(allocator)
标准接口:
vlaue_type
pointer
const_pointer
reference
const_reference
size_type
difference_type
rebind
allocator()--default constructor
allocator(const allocator<U>&--copy constructor
~allocator()--destructor
address(reference x)const--return address of elem
address(const_reference x)const
allocate(size_type n, const void*= 0)--alloc memory
deallocator(pointer p, size_type n)--return memory
max_size()--return memory alloc succesfully
construct(pointer p, const T& x)--=new((void*) p) T(x)
destroy()--=p->T()
STL allocator把内存配置和对象的构造分开
allocate负责内存配置,deallocate负责内存的释放
construct负责对象构造,destroy负责对象析构
SGI std::alloc设计思想:
1.向system heap要求空间
2.考虑多线程状态
3.考虑内存不足的应变措施
4.考虑过多小型区块导致的内存碎片问题
以malloc和free完成内存的配置与释放
考虑过多小型区块导致的内存碎片问题,SGI设计了双层配置器
1.当配置区块大于128bytes时,调用第一级配置器,直接使用malloc和free
2.当配置区块小于128bytes时,调用第二级配置器,采用内存池的整理方式
第一级配置器:
1.allocate直接使用malloc
2.deallocate直接使用free
3.当内存不足时,用malloc free realloc执行实际的内存配置、释放、重配置操作,以实现出类似于c++中new-handler的机制
new-handler的机制:可以要求系统在内存配置需求无法满足的情况下,调用一个你指定的函数
==>一旦new无法完成任务,在丢出bad_alloc异常之前可以先调用指定的处理函数
第二级配置器:
当配置的内存较小时,用内存池的方式管理(次层配置):
每次配置一大块内存,并且维护一个自由链表,下次若有相同大小的内存需求,则直接从自由链表中取出,若有释放的内存则收入到自由链表中。
为方便管理,将任何小额区块的内存需求量上调至8的倍数
当自由链表中没有可用区块时调用refill,为自由链表重新填充空间。
新的空间将由chunk_alloc完成
chunk_alloc:
判断内存池中的内存,若果足够,则分出20个区块给自由链表
如果不足20个,但至少有一个,则有多少拨多少
如果一个都没有,则利用malloc从heap中配置内存,注入内存池中
要是整个system heap中内存都不够了,则寻找是否有尚有未用区块且区块足够大的自由链表,有的话就挖出来用
如果还没有,则调用第一级配置器,new-handler机制
如果还不行,就bad_alloc异常
内存基本处理工具:
uninitialized_copy:为了将内存的配置跟对象的构造分离开来,对调用拷贝构造函数来构造未初始化区域中的对象,调用construct
调用的结果是要么构造出全部对象,要么就什么都没有
uninitialized_fill
uninitialized_fill_n
上述三个函数分别对应高层的STL算法copy(),fill(),fill_n()