目录
一.SGI的配置器
SGI设计了双层级配置器:1.当配置区块超过128字节,调用第一级配置器,即间接调用malloc()和free();2.当配置区快小于128字节,视之为“过小”,采用第二级配置器。
二.第一级配置器(malloc_alloc)
SGI的第一级配置器allocator()和reallocate()都是在间接调用malloc()和realloc(),当malloc()和realloc()无法满足要求时,改用oom_malloc()和oom_realloc()。在此以allocator()为例,realloc()类似:
static void * allocate(size_t n)
{
void *result = malloc(n);
if(0 == result) result = oom_malloc();//当malloc()无法满足时,改用oom_malloc()
return result;
}
三.第二级配置器
当要配置的内存空间小于128字节时,调用第二级配置器。
3.1 几点说明
1.第二级配置器中最重要的就是联合体指针union变量free_list[16],该数组中存储的obj*类型变量不仅可以指向从内存池中申请到多个区块的首地址,且obj联合体中的free_list_link指针也可以存储指向下一个相同大小区块的地址。由于free_list[n]数组有16个数组元素,则每一个数组元素指向大小为n*8的区块链表,最后一个数组元素指大小为128字节的区块:
union obj{
union obj * free_list_link;
char client_data[1];
};
static obj * volatile free_list[16];
2.free_list[16]数组存储的区块地址是来自于内存池中的,由于内存池的地址是有限的,所以需要两个指针指出可用内存池地址的前后地址:
static char *start_free;//只在chunk_alloc()中变化
static char *end_free;//只在chunk_alloc()中变化
3.2 空间配置器allocate()
-
当大于128字节时,调用第一级配置器malloc_alloc()。
-
当小于128字节时:
-
根据传入的大小n决定要使用的区块元素:
obj * volatile * my_free_list = free_list + FREELIST_INDEX(n);//当n=90时,FREELIST_INDEX(n)=11,从而使用free_list[11]
- 指向该数组元素(obj类型的指针)的地址:
obj * result = *my_free_list;
- 调整第12个数组元素free_list[11],使之存储下一个大小为12*8字节大小的区块:
*my_free_list = result->free_list_link;
- 返回result(类型为obj *,返回时由于函数的返回值类型为void *,强制转化为void *)变量。
3.3 重新填充(refill(size_t n))
该函数用于allocator()函数在配置内存时,free_list[16]数组中的元素没有存储指向对于大小的区块地址(值为NULL)时,对该元素重新分配指向数个对应大小区块组成的链表。
- 利用chunk_alloc()函数从内存池中取出对应大小的数个区块(个数由具体内存池大小决定,大小够时,默认建立20个对应大小的区块):
char * chunk = chunk_alloc(n, nobjs);//n表示上调至8的倍数的字节数;nobjs表示实际配置的区块个数,由于函数传得是引用,所以nobjs的值会直接受到函数的修改
- 如果从内存池中取出的区块个数为1,则直接传递给allocate()函数使用,否则调整free_list数组,纳入新节点:
obj * result = (obj *)chunk;//这个区块返回给客户端使用
*my_free_list = next_obj = (obj *)(chunk + n);
//将free list的各节点串起来
for(int i = 1; ; i++)
{
current_obj = next_obj;
next_obj = (obj *)((char *)next_obj + n);
if(nobjs - 1 == i){
current_obj -> free_list_link = 0;
break;
} else {
current_obj -> free_list_link = next_obj;
}
}
四.对第一级和第二级配置器进行封装
template<class T, class Alloc>//Alloc传入第一级或者第二级配置器
class simple_alloc{
public:
static T *allocate(size_t n)
return 0 == n? 0 : (T*) Alloc::allocate(n * sizeof(T));
static T * allocate(void)
return (T*) Alloc::allocate(sizeof(T));
static void deallocate(T *p, size_t n)
if(0 != n) Alloc::deallocate(p, n * sizeof(T));
static void deallocate(T *p)
if(0 == n) Alloc::deallocate(p, sizeof(T));
};