为什么要有空间配置器呢?这主要是从两个方面来考虑的。
1、小块内存带来的内存碎片问题
单从分配的角度来看。由于频繁分配、释放小块内存容易在堆中造成外碎片(极端情况下就是堆中空闲的内存总量满足一个请求,但是这些空闲的块都不连续,导致任何一个单独的空闲的块都无法满足这个请求)。
2、小块内存频繁申请释放带来的性能问题。
关于性能这个问题要是再深究起来还是比较复杂的,下面我来简单的说明一下。
开辟空间的时候,分配器会去找一块空闲块给用户,找空闲块也是需要时间的,尤其是在外碎片比较多的情况下。如果分配器其找不到,就要考虑处理假碎片现象(释放的小块空间没有合并),这时候就要将这些已经释放的的空闲块进行合并,这也是需要时间的。
malloc在开辟空间的时候,这些空间会带有一些附加的信息,这样的话也就造成了空间的利用率有所降低,尤其是在频繁申请小块内存的时候。
为了解决上面这些问题,所以就提出有了内存池的概念。内存池最基本的思想就是一次向heap申请一块很大的内存(内存池),如果申请小块内存的话就直接到内存池中去要。这样的话,就能够有效的解决上面所提到的问题。
下面我们来剖析一下STL里面的空间配置器(SGI版)。
STL里面的空间配置主要分为两级,一级空间配置器(__malloc_alloc_template)和二级空间配置器(__default_alloc_template)。在STL中默认如果要分配的内存大于128个字节的话就是大块内存,调用一级空间配置器直接向系统申请,如果小于等于128个字节的话则认为是小内存,则就去内存池中申请。一级空间配置器很简单,直接封装了malloc和free处理,增加_malloc_alloc_oom_handle处理机制。二级空间配置器才是STL的精华,二级空间配置器主要由memoryPool+freelist构成。
一级空间配置器:
执行流程:
SGI以malloc来配置内存。当malloc()失败后,就调用oom_alloc(),如果客户端没有设置内存不足处理机制,则就直接抛出bad_alloc异常信息,或者直接终止程序。如果客户端设置了内存不足处理机制,则他就会一直调用内存处理机制,企图在某次调用之后获得一块足够的内存。但是如果内存不足处理机制设计不好的话,存在死循环的危险。
注意:"内存不足处理机制"是客户端的责任,设置"内存不足处理介质"也是客户端的责任。
程序:
typedef void(*MALLOCALLOC)(); //将void (*)() 重命名成MALLOCALLOC
template<int inst>
class _MallocAllocTemplate
{
private:
static void* _OomMallo