前言
在上一篇博文中介绍了第一级空间配置器 ,在第一级空间配置器中,本质上还是使用的malloc来进行空间分配。如果分配的空间较小的时候,使用malloc会导致cookie这些额外空间开销过大(这里可以参考【内存管理】模块的博文)。因此SGI采用二级空间配置器去避免较大的额外开销,更加充分的利用好内存空间。下面介绍第二级空间配置器。
一、二级空间配置器__default_alloc_template
二级空间配置器采用了内存池的设计,整个设计让人看了觉得特别有意思~
1、设计思路:
(1)当分配较多较小空间的内存的时候,每个小空间都带有cookie(纪录当前内存块的大小)等额外空间。因此考虑将cookie采用共用的形式,多个同样大小的小空间共用一个cookie。
(2)采用内存池进行内存的分配和回收。内存池通过自由链表去实现。STL中用free_list去表示这块内存空间。
(3)如果采用链表去分配空间的话,需要使用指针去指向下一个位置,那么就会产生内存消耗。为了节省内存空间,STL中采用union(嵌入式指针)。【嵌入式指针可以参考模块对应的博文】
//这个结构就相当于把一块内存区域复用:(1)数据存储的块(2)块位置的下一个位置
union obj{
union obj * free_list_link; //这个应该表示的是free_lists自由链表上某一块区域的下对应的指针
char client_data[0]; //这个应该表示的是用户需要存储的数据
}
关于其中的一些问题&个人理解:
(1)用free_list[i]就是一个上面union结构,其中用嵌入式指针存储了自由链表free_list中第i块下的链表。
下面是第二级空间配置器的部分实现:
//enum是表示枚举值
enum {
__ALIGN = 8}; //小型区块的上调边界
enum {
__MAX_BYTES = 128}; //小型区块的上限。对于区块大于128的直接采用一级空间配置器
enum {
__NFREELISTS = __MAX_BYTES / __ALIGN}; //free_list的个数
//以下是第二级空间配置器
//无template类型参数,不考虑多线程的情况
template <bool threads, int inst>
class __default_alloc_template{
private:
//ROUND_UP将bytes上调至8的倍数
//这个是为了字节对齐
static size_t ROUND_UP(size_t bytes){
return (bytes + __ALIGN - 1) & ~(__ALIGN - 1); //没太懂,8是1000,8 - 1 = 7 也就是 111
//这里一般来说上调至8的倍数,应该是 n + (8 - n%8)
}
union obj{
union obj *free_list_link;
char client_data[1];
}
static obj* volatile free_list[__NFREELISTS]; //自由链表数据
static size_t FREELIST_INDEX(size_t bytes){
return (((bytes) + __ALIGN - 1) / __ALIGN - 1);
}
static void *refill(size_t n);
//配置一大块空间,可容纳nobjs个大