提纲:本文主要分析STL一级空间配置器的源代码并模拟实现一级空间配置器
一、什么是STL
STL(standard Template Library,标准模板库),是算法和一些组件的结合,STL有六大组件,彼此可以组合套用,六大组件分别是
1、容器(containers):各种数据结构,如vector,list,deque,set,map等,用来存放数据。
2、算法(algorithms):各种算法如sort,search,copy,erase等。
3、迭代器(iterators):扮演容器与算法之间的胶合剂,共有五种类型。
4、仿函数(functors):行为类似函数,可作为算法的某种谋略。
5、配接器(adapters):一种用来修饰容器或仿函数或迭代器接口的东西。
6、配置器(allocators):负责空间配置与管理。
二、空间配置器
1、什么是空间配置器
整个STL操作的数值都存放在容器中,而容器是需要空间配置器来管理和分配空间的。
注:这里所指的空间不单单指内存,也可以是磁盘或者其他存储介质。
2、空间配置器的设计思想
(1)向system heap索要空间;
(2)内存不足的应变措施;
(3)解决内存碎片问题。
SGI STL设置了两级空间配置器,一级空间配置器底层用malloc()和free()来实现;二级空间配置器采用了内存池的处理方式。
三、剖析一级空间配置器源代码
1、剖析源代码
一级空间配置器以malloc(),free(),realloc()等C语言函数来实现空间的配置、释放、重配置。
我们来看具体的源代码
//一级空间配置器
template <int __inst>
class __malloc_alloc_template {
private:
//以下函数用来处理内存不足的情况
static void* _S_oom_malloc(size_t);
static void* _S_oom_realloc(void*, size_t);
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
//内存不足处理例程
static void(*__malloc_alloc_oom_handler)(); //__malloc_alloc_oom_handler是函数指针
#endif
public:
//空间配置函数
static void* allocate(size_t __n)
{
//用malloc申请空间
void* __result = malloc(__n);
//如果申请空间失败,则调用_S_oom_malloc重新申请空间
if (0 == __result) __result = _S_oom_malloc(__n);
return __result;
}
//空间释放函数
static void deallocate(void* __p, size_t /* __n */)
{
//调用free来释放空间
free(__p);
}
//空间重配置函数
static void* reallocate(void* __p, size_t /* old_sz */, size_t __new_sz)
{
//用realloc来重新配置空间
void* __result = realloc(__p, __new_sz);
//如果由于空间不足配置失败,则调用_S_oom_realloc重新申请空间
if (0 == __result) __result = _S_oom_realloc(__p, __new_sz);
return __result;
}
//该函数重新指定了内存分配异常处理函数,并返回了原有的内存分配异常处理函数
//该函数接受一个“返回值和参数均为空的函数指针”作为参数
//该函数最后返回一个“返回值和参数均为空的函数指针”
static void (* __set_malloc_handler(void (*__f)()))()
{
void (* __old)() = __malloc_alloc_oom_handler;
//重新指定内存分配异常处理函数
__malloc_alloc_oom_handler = __f;
//返回原有的内存分配异常处理函数
return(__old);
}
};
// malloc_alloc out-of-memory handling
#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int __inst>
//内存不足处理例程,初始值为0,待用户自定义,考虑内存不足时的应变措施
void (* __malloc_alloc_template<__inst>::__malloc_alloc_oom_handler)() = 0;
#endif
template <int __inst>
//申请空间失败时调用_S_oom_malloc重新申请空间
void* __malloc_alloc_template<__inst>::_S_oom_malloc(size_t __n)
{
//定义一个函数指针__my_malloc_handler
void (* __my_malloc_handler)();
void* __result;
//该循环有两个退出条件
//一个是成功申请到空间,最终返回__result
//另一个是最终申请空间失败,抛出异常__THROW_BAD_ALLOC
for (;;) {
__my_malloc_handler = __malloc_alloc_oom_handler;
//由于初值为0,如果用户没有自定义内存不足处理例程,那么还是抛出异常
if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }
//调用内存不足处理例程,尝试释放空间
(*__my_malloc_handler)();
//再次尝试配置空间
__result = malloc(__n);
if (__result) return(__result);
}
}
template <int __inst>
//重新配置空间失败时调用_S_oom_realloc申请空间
void* __malloc_alloc_template<__inst>::_S_oom_realloc(void* __p, size_t __n)
{
//定义一个函数指针__my_malloc_handler
void (* __my_malloc_handler)();
void* __result;
//该循环有两个退出条件
//一个是成功申请到空间,最终返回__result
//另一个是最终申请空间失败,抛出异常__THROW_BAD_ALLOC
for (;;) {
__my_malloc_handler = __malloc_alloc_oom_handler;
//由于初值为0,如果用户没有自定义内存不足处理例程,那么还是抛出异常
if (0 == __my_malloc_handler) { __THROW_BAD_ALLOC; }
//调用内存不足处理例程,尝试释放空间
(*__my_malloc_handler)();
//再次尝试配置空间
__result = realloc(__p, __n);
if (__result) return(__result);
}
}
//由于参数inst在这里没有排上用场,因此定义为数值0
typedef __malloc_alloc_template<0> malloc_alloc;
2、小结
通过对源代码的剖析,我们可以看出:SGI STL一级空间配置器是通过调用malloc()函数,realloc()函数进行申请空间,当申请空间失败后便调用_S_oom_malloc()函数和_S_oom_realloc()函数重新申请空间,而这两个函数都会调用“内存不足处理例程”来尝试释放空间,期望能在某次释放空间后得到一块足够大小的内存,但是如果客户端不设定“内存不足处理例程”的话,程序便会抛出异常。
通过下图来表示我对一级空间配置器的理解:
四、模拟实现一级空间配置器
通过对以上源代码的剖析,根据自己的理解,尝试模拟实现一级空间配置器,具体代码如下
//一级空间配置器
template <int inst>
class MallocAllocTempalte
{
public:
//分配空间
static void* Allocate(size_t n)
{
void* ret = malloc(n);
//如果申请失败就调用OOM_Malloc()函数
if (NULL == ret)
ret = OOM_Malloc(n);
return ret;
}
//模拟C++的set_new_handler
static void(*set_malloc_handler(void(*f)())) ()
{
//保存原有处理例程
void(*old)() = MallocAllocOOMHandler;
//重新指定内存不足处理例程
MallocAllocOOMHandler = f;
return old;
}
//处理分配空间时的内存不足情况
void* OOM_Malloc(size_t n)
{
void* ret = NULL;
while (1)
{
if (NULL == MallocAllocOOMHandler)
throw bad_alloc();
//再次处理例程,尝试释放内存
(*MallocAllocOOMHandler)();
//尝试重新分配内存
ret = OOM_Malloc(n);
if (ret)
return ret;
}
}
//释放空间
void Deallocate(void* p)
{
free(p);
}
//重新分配空间
void* Reallocate(void* p, size_t n)
{
void* ret = Reallocate(p, n);
if (NULL == ret)
ret = OOM_Realloc(p, n);
return ret;
}
//处理重新分配空间时的内存不足情况
void* OOM_Realloc(void* p, size_t n)
{
void* ret = NULL;
while (1)
{
if (NULL == MallocAllocOOMHandler)
throw bad_alloc();
//调用例程,尝试释放空间
(*MallocAllocOOMHandler)();
//再次配置空间
ret = OOM_Realloc(p, n);
if (ret)
return ret;
}
}
private:
//处理用malloc分配内存时内存不足的情况
static void* OOM_Malloc(size_t);
//处理用realloc分配内存时内存不足的情况
static void* OOM_Realloc(void*, size_t);
//指针MallocAllocOOMHandler指向一个无参数并且返回值也为空的函数
static void (*MallocAllocOOMHandler) ();
};
template <int __inst>
//内存不足处理例程,初始值为0,待用户自定义,考虑内存不足时的应变措施
void(*MallocAllocTempalte<__inst>::MallocAllocOOMHandler)() = 0;
typedef MallocAllocTempalte<0> malloc_alloc;