空间配置器 之 内存的配置与释放

目录

一.SGI的配置器

二.第一级配置器(malloc_alloc)

三.第二级配置器

3.1 几点说明

3.2 空间配置器allocate()

3.3 重新填充(refill(size_t n))

四.对第一级和第二级配置器进行封装


一.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()

  1. 当大于128字节时,调用第一级配置器malloc_alloc()。

  2. 当小于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));
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值