近来闲来无趣,看了下STL的空间配置器。
首先恭喜我入坑,网上无数的人都在剖析这STL的空间配置器,所以,刚好,今天我也加入了这个团队,这个应该是我目前看到的比较完整架构的一个源码了吧,希望能提示我的水平,毕竟设计的很好。在这里特别说下,没有操作系统的知识,所以在这里的线程和锁的这些问题,我们一概不讨论
STL的空间配置器,就是一个为了给容器进行分配内存和管理内存的东西,容许我盗几张图给大家说明。
这个是整个STL的一个结构,后续我会再写博客对这些进行分析。
1.为什么会利用SGI的空间配置器?
首先这个问题具有很强的目的性,因为接触一个东西只有了解了怎么样用才是最快的学习方式之一。
空间配置器而言是对内存管理,所以解决的问题就是内存上的容易出现的问题。所以我们先来看内存上会出现什么问题?
这个时候就会出问题了,这个时候就会出现一个外碎片的问题。这个时候的碎片处理方式就可以进行优化,STL当中也就考虑到了这种情况。
另外一个问题就是,对于很多情况下,我们经常会做一些大量的内存分配与释放,比如说在高并发的情况下,但是,在这种情况下,如果你每次都对操作系统进行分配请求与释放请求,这样毫无疑问,效率非常低下,所以,作为提倡效率的一门语言,C++充分的考虑了这个问题。
接下来,就让我们去瞧一瞧。
2.SGI空间配置器的接口
首先我们来看看关于接口部分当我们对一个容器进行new 的时候,在这里提供了一个宏__USE_MALLOC,定义了这个宏,调用第一级配置器,没有定义的,调用第二级配置器。另外就是,接下来,STL 为了让整个符合规范化,在这里,STL封装了一个类叫做simple_alloc,通过这个接口,我们来调用空间配置器进行内存管理。
3.SGI空间配置器的一级空间配置器
接下来所说的一级空间配置器,一级空间配置器是一个叫做__malloc_alloc_template的类,首先我们需要知道,只有当在要求分配字节数在128个字节以上的时候这个时候才会去调用一级分配器,这个时候所以简单的也就是采用了malloc和free机制,不过,设计STL的人很聪明,在这为了要求对空间利用的最大化,它在这里还考虑了out of memory机制。
template <int inst>
class __malloc_alloc_template {
private:
static void *oom_malloc(size_t); //处理内存不够的函数
static void *oom_realloc(void *, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
static void (* __malloc_alloc_oom_handler)(); //处理内存不够的一个句柄
#endif
public:
static void * allocate(size_t n)
{
void *result = malloc(n); //进行分配n个内存空间
if (0 == result) //判断是否分配成功
result = oom_malloc(n); //内存分配不成功,进入OOMMalloc查看是否可以操作系统释放内存分配,如果无法分配,抛出异常。
return result;
}
//第一级空间配置器直接使用free
static void deallocate(void *p, size_t /* n */)
{
free(p);
}
static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
void * result = realloc(p, new_sz);
if (0 == result) result = oom_realloc(p, new_sz);
return result;
}
//通过这个函数设置文件句柄,从而间接实现set_new_handler。
static void (* set_malloc_handler(void (*f)()))()
{
void (* old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f; //设置文件句柄
return(old); //返回旧的,操作系统惯用写法。
}
这里我想你就知道了,为什么说new是抛异常了,也会发现这个设计者所做的很好了,尤其是set_new_handler的机制,可以通过这个达到了,对内存的最大利用,当然,new-handler函数需要自己设计,一个好的new-handler函数是非常重要的,否则就非常坑了,关于这里的问题如果不清楚,也可以去参考 effective c++。’
4.SGI空间配置器的二级空间配置器
当对象所需内存大于128个字节的时候,这个时候我们就需要去调用第二级空间配置器。
这个时候我们进行维护的就是16个自由链表,这16个自由