您的位置:首页 > 其它

SGISTL源码探究-第一级配置器

2017-09-06 15:40 239 查看

前言

在本小节中,我们主要介绍第一级配置器的做法。

第一级配置器(__malloc_alloc_template)

引入

第一级配置器用于处理大于128bytes的情况,即申请大的内存。直接使用
malloc
free
申请释放即可。(现在有可能不是以128bytes为标准了,不过源码本来就是主着学习的目的,不管现在是多少,至少你能从中学到思想就够了)

深入源码

//这里是一个模板偏特化技术,即int类型,可以提供不同的实例,比如__malloc_alloc_template<0>和__malloc_alloc_template<1>就是两个不同的版本。这样做的好处是拥有不同的static。
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);
static void (*__malloc_alloc_oom_handler)();
public:
//用malloc申请n个大小的空间
static void *allocate(size_t n)
{
void *result = malloc(n);
//如果失败了,则调用处理函数
if(0 == result) result = oom_malloc(n);
return result;
}
//用free释放空间
static void deallocate(void *p, size_t )
{
free(p);
}
//用realloc重新申请空间
static void *reallocate(void *p, size_t, size_t new_sz)
{
void *result = realloc(p, new_sz);
//如果失败了,则调用处理函数
if(0 == result) result = oom_realloc(p, new_sz);
return result;
}

//这里实际上是模仿了操作符new里面的`set_new_handler()`函数,可以让用户自己定义内存不足时的处理函数,并返回旧的处理方法。(这里的参数还有样子可以看起来有点绕,其实就是两个函数指针,返回的类型是函数指针,传入的参数也是函数指针)
static void (* set_malloc_handler)(void (*f)())()
{
void (*old)() = __malloc_alloc_oom_handler;
__malloc_alloc_oom_handler = f;
return (old);
}
};


接下来就是oom部分

template <int inst>
void (*__malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;

//当malloc申请内存不足时
template <int inst>
void *__malloc_alloc_template<inst>::oom_malloc(size_t n)
{
//引入局部函数指针
void (*my_malloc_handler)();
void *result;

//注意,这是一个死循环,要么申请内存成功,要么抛出异常。否则一直执行出错处理程序。(这和new里面的机制是一样的)
for(;;)
{
my_malloc_handler = __malloc_alloc_oom_handler;
//如果__malloc_alloc_oom_handler为null的话,那么直接抛出异常
if(0 == my_malloc_handler)
{
__THROW_BAD_ALLOC;
}
//否则调用处理程序
(*my_malloc_handler)();
//尝试分配,如果失败,重新循环;如果成功了,退出
result = malloc(n);
if(result) return (result);
}
}

//oom_realloc和oom_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);
}
}

typedef __malloc_alloc_template<0> malloc_alloc;


分析

在第一级配置器中,当
malloc
realloc
分配内存不成功时,会调用各自的
oom_xxx
,里面会调用用户自己设置的
__malloc_alloc_oom_handler
,如果成功申请,则返回,否则当用户没有设置
__malloc_alloc_oom_handler
时,就直接抛出异常了,如果设置了,则调用处理程序,然后又如此反复。该机制和
new
的确类似,如果你已经了解
new
的做法,那么这个就很容易理解了。

至于那个
template <int inst>
,如果将其直接实现为类,假设有多个实例,会有点问题。我们都知道
static
变量在类中只会被保留一份,如果将
__malloc_alloc_template
实现成简单的类,那么每次实例化对象的时候,
__malloc_alloc_oom_handler
都是上一次改变的值,而我们要求的是,应该由用户自己来定义处理程序,所以应该每次使用一个新的一级配置器时,处理程序的初始值都该为null。(你可能会想,那就不用
static
关键字,别忘了
static
还有隐藏变量和函数的作用,用于封装)。不过,事实上我们根本不用担心这么多,因为最后一行代码直接将
__malloc_alloc_template<0>
typedef成了
malloc_alloc
,只用了一个一级配置器。

小结

在本小节中,主要介绍了第一级配置器中申请以及释放内存的做法,申请内存时类似
new
操作符的机制。使用第一级配置器还是第二级配置器主要是根据要求分配的空间大小来定。在下一小节我们主要分析第二级配置器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: