一、实现
1、为了精密分工,STL allocator将两阶段操作分开,内存配置操作由alloc::allocate()负责,内存释放操作由alloc::deallocate()负责
对象构造操作由::construct()负责,对象析构操作由::destroy()负责
2、对象构造前的空间配置和对象析构后的空间释放,由<stl_alloc.h>负责,SGI对此的设计哲学如下:
向system heap要求空间
考虑多线程状态
考虑内存不足时的应变措施
考虑过多“小型区块”可能造成的内存碎片问题
3、考虑到小型区块所可能造成的内存破碎问题,SGI设计了双层级配置器,第一级直接使用malloc和free,第二级视情况采用不同策略。
4、第一级配置器以malloc、free、realloc等C函数执行实际的内存配置、释放、重配置等操作,并实现出类似C++ new-handler的机制
,它不能直接运用C++ new-handler的机制,因为它并非使用::operator new来配置内存。
5、所有C++ new-handler的机制是:你可以要求系统在内存配置需求无法被满足时,调用一个你所指定的函数。
换句话说,一旦::operator new无法完成任务,在丢出std::bad_alloc异常状态之前,会先调用由客户端指定的处理例程,该处理
例程通常即被称为new-handler。
6、SGI第二级配置器的做法:如果区块够大,超过128bytes时,就移交第一级配置器处理,当区块小于128bytes时,则以内存池管理,
此法又称为次层配置:每次配置一大块内存,并维护对应之自由链表,下次若再有相同大小的内存需求,就直接从自由链表中拨出,
如果释放小额区块,就由配置器回收到自由链表中。
7、SGI第二级配置器会主动将任何小额区块的内存需求量上调至8的倍数,并维护16个free-lists,各自管理大小分别为8,16,32,,,128的
小额区块。
8、索求任何一块内存,都得有一些“税”要交给系统。
二、内存基本处理工具
1、STL定义了5个全局函数,作用于未初始化空间上。
construct
destroy
uninitialized_copy 对应于高层次函数 copy
uninitialized_fill 对应于高层次函数 fill
uninitialized_fill_n 对应于高层次函数 fill_n
2、copy作用
uninitialized_copy使我们能够将内存的配置与对象的构造行为分离开来。
如果你需要实现一个容器,uninitialized_copy这样的函数会为你带来很大的帮助,因为容器的全区间构造函数通常以两个步骤完成:
配置内存区块,足以包含范围内的所有元素
使用uninitialized_copy,在该内存区块上构造元素。
C++标准规格书要求uninitialized_copy具有“commit or rollback”语意,意思是要么“构造出所有必要元素”,要么“不构造
任何东西”。
3、fill作用
uninitialized_fill也使我们能够将内存的配置与对象的构造行为分离开来。
3、fill_n作用
uninitialized_fill_n也使我们能够将内存的配置与对象的构造行为分离开来。
三、相关术语
1、POD
意思是 Plain Old Data,也就是标量型别或传统的C struct型别。POD型别必然拥有 trivial ctor/dtor/copy/assignment函数。
四、总结
空间配置器总是隐藏在一切组件的背后,默默工作,默默付出。
因为整个STL的操作对象都存放在容器之内,而容器一定需要配置空间以置放资料。
为什么不说allocator是内存配置器而说是空间配置器呢?
因为空间不一定是内存,空间也可以使磁盘或其他辅助存储介质。
是滴,你可以写一个allocator,直接向硬盘取空间。