SGISTL源码阅读一 空间配置器上(第一级配置器__malloc_alloc_template)
引入
我们所熟知的C++内存配置操作一般为
class A {}
A* pa = new A(); //1.分配内存 2.构造对象
delete pa; //1.对象析构 2.释放内存
其中new
完成了两个操作
1.调用operator new
配置内存
2.调用A::A()构造对象
这样做没有考虑到任何效率上的强化,如果有些空间根本不会被用到,那么构造对象完全就是一种浪费。
而STL中的alloc将new
所完成的操作拆分开来,SGISTL源码中有两个文件,stl_alloc.h
负责内存空间的配置与释放,stl_construct.h
负责对象内容的构造与析构。
SGI特殊的空间配置器
对象构造前的空间配置和对象析构后的空间释放,由stl_alloc.h
负责。
考虑到小型区块可能造成的内存破碎问题,SGI设计了双层级配置器。
第一级配置器用于处理大于128bytes的情况,即申请大的内存,第二级配置器用于申请小内存。
第一级配置器(__malloc_alloc_template)
直接使用malloc()
和 free()
即可,我们来深入源码探究。
//这里用到了模板全特化技术
template <int inst>
class __malloc_alloc_template {
private:
/*
*oom(out of memory)
*下面的函数用于处理内存不足的情况
*/
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:
//申请n个大小的空间
static void * allocate(size_t n)
{
void *result = malloc(n);
if (0 == result) result = oom_malloc(n);
return result;
}
//释放空间
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;
}
/*
*这是一个返回值为函数指针的指针函数(传送门:https://blog.csdn.net/lyn_00/article/details/83549655)
*仿真C++的set_new_handler()
*它的作用是可以让用户自己定义内存不足时的处理函数,并返回旧的处理方法
*/
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>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
#endif
template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
//局部函数指针,用于指向用户字定义处理函数
void (* my_malloc_handler)();
void *result;
/*
*如果用户没有定义内存不足时的处理函数,则抛出一个异常,反之,则申请到内存正常退出
*我们可以注意到这是一个死循环,但是也不难理解,因为必须对内存不足这种情况做好处理
*/
for (;;) {
my_malloc_handler = __malloc_alloc_oom_handler;
if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; }
(*my_malloc_handler)();
result = malloc(n);
if (result) return(result);
}
}
//realloc和malloc类似
template <int inst>
void * __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n)
{
void (* my_malloc_handler)();
void *result;
for (;;) {
my_malloc_handler = __malloc_alloc_oom_handler;
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;
总结
以上主要对SGI中空间配置器的第一级配置器进行了分析。它如何申请释放内存,以及对内存不足时的处理。第二级配置器比第一级配置器要复杂得多,将会在下一篇博客中介绍。