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操作符的机制。使用第一级配置器还是第二级配置器主要是根据要求分配的空间大小来定。在下一小节我们主要分析第二级配置器。
相关文章推荐
- SGISTL源码探究-第二级配置器
- SGISTL源码探究-默认使用的配置器
- SGISTL源码探究-关联式容器:hash_set
- SGISTL源码探究-优先级队列
- SGISTL源码探究-STL中的hashtable(下)
- SGISTL源码探究-stl_alog.h中的二分查找算法
- SGISTL源码探究-迭代器的类型
- STL源码分析--空间配置器 第一级配置器
- SGISTL源码探究-stl_algo.h中的排列算法
- SGISTL源码探究-配接器
- SGISTL源码探究-list容器(上)
- SGISTL源码探究-STL中的红黑树(上)
- SGISTL源码探究-STL中的红黑树(下)
- SGISTL源码探究-STL中的算法(前言)
- SGISTL源码探究-stl_algo.h中的排序算法
- SGISTL源码探究-stl_algo.h中的基础算法
- SGISTL源码探究-STL中的hashtable(上)
- SGISTL源码探究-大根堆heap
- SGISTL源码探究-关联式容器:set
- Azkaban的Web Server源码探究系列15:使用过程中几个需注意的配置&3.0中丢失的文件