您的位置:首页 > 其它

STL学习_SGI二级空间配置器源码剖析

2016-04-28 19:39 411 查看
//二级空间配置器 __defaule_alloc_template

如果感觉光看代码难以理解,可以看看上篇博客介绍了二级空间配置器是怎样进行内存分配的。

enum{__ALIGN = 8};//最小申请的空间的大小

enum{__MAX_BYTES = 128};//能最大申请的空间的大小

//SGI第二配置器有16个free_lists

enum{__NFREELISTS = __MAX_BYTES / __ALIGN};//free_lists的个数

template<bool threads, int inst>

class __default_alloc_template

{

private:

//将客户申请的空间的大小上调至8的倍数

static size_t ROUND_UP(size_t bytes)

{

return (((bytes) + __ALIGN-1)&~(__ALIGN - 1));

}

private:

//16个free_lists的节点结构

//union能够实现一物两用的效果,1.obj可被视为一个指针,指向相同形式的另一 //个obj。2.obj可被视为一个指针,指向实际区块。

union obj{

union obj * free_list_link;//指向下一个节点的指针

char client_data[1];//记录此时节点数据

};

private:

static obj * volatile free_list[__NFREELISTS];//16个free_lists

//计算客户申请的空间的大小在哪个free_lists自由链表

static size_t FREELIST_INDEX(size_t bytes)

{

return (((bytes) + __ALIGN-1)/ __ALIGN - 1);

}

static char *start_free;//内存池起始位置

static char *end_free;//内存池结束位置

static size_t heap_size;//附加量

private:

static void *refill(size_t n);

static char *chunk_alloc(size_t size, int &nobjs);

public:

//空间配置函数

static void *allocate(size_t n)

{

obj * volatile * my_free_list;

obj * result;

//客户申请的空间大于128采用一级空间配置器进行空间的申请

if(n > (size_t __MAX_BYTES){

return (malloc_alloc::allocate(n));

}

//my_free_list这个二级指针指向客户申请空间大小适合的自由链表free_lists

my_free_list = free_list + FREELIST_INDEX(n);

//*my_free_list这个指针指向的是相对应的还没有给客户端分配的自由链表的起始

//位置

result = *my_free_list;

//没有找到可用的free_list,准备查看有没有可用的内存池来填充自由链表

if(0 == result){

void *r = refill(ROUND_UP(n));

return r;

}

//找到可用的自由链表,调整自由链表,让*my_free_list这个指针指向还没有给客 //户分配的自由链表的起始位置,也就是result的下一个节点的位置

*my_free_list = result->free_list_link;

return result;

}

//空间释放函数

static void deallocate(void *p, size_t n)

{

obj *q = (obj *)p;

obj * volatile * my_free_list;

if(n > (size_t)__MAX_BYTES){

malloc_allloc::deallocate(p, n);

return;

}

//释放已经给客户分配出去的p空间,也就是让p空间重新连接到自由链表上

//也就是先让p空间的指针指向下个节点也就是自由链表的起始位置,然后让自由链 //表的起始位置重新指向p空间

my_free_list = free_list + FREELISTS_INDEX(n);

q->free_list_link = *my_free_list;

*my_free_list = q;

}

};

//对__default_alloc_template这个类内的数据成员的定义与初值设定

template<bool threads, int inst>

char *__default_alloc_template<tnreads, inst>::start_free = 0;

template<bool threads, int inst>

char *__default_alloc_template<threads, inst>::end_free = 0;

template<bool threads, int inst>

size_t __default_alloc_template<threads, inst>::head_size = 0;

//这里的数据成员free_list,由于free_list的类型obj * volatile是模板类型声明的

//并且这个函数名也是模板类型内声明的,所以这里对free_list的定义与处值的设定

//用两个模板类__default_alloc_template<threads, inst>

template<bool threads, int inst>

__default_alloc_template<thread, inst>::obj * volatile

__default_alloc_template<threads, inst>::free_list[__NFREELISTA]=

{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};

//重新填充函数,当发现自由链表没有可用区块了,就调用这个函数从内存池中找到空间

//重新填充自由链表

template<bool threads, int inst>

void *__default_alloc_template<threads, inst>::refill(size_t n)

{

int nobjs = 20;

char *chunk = chunk_alloc(n, nobjs);

obj * volatile * my_free_list;

obj * result;

obj *current_obj, *next_obj;

int i;

//如果只获得一个区块,把这个区块给客户,free_list没有可用的节点了

if(1 == nobjs){

return (chunk);

}

my_free_list = free_list + NFREELIST_INDEX
;

result = (obj *)chunk;//这一块准备返回给客户

//chunk指向的是新free_list的起始位置,这里让*my_free_list指向新配置的

//空间,取自内存池

*my_free_list = next_obj = (obj *)(chunk + n);

//将free_list的各个节点用指针串起来,从第一个开始,因为第零个区块

//要返回给客户

for(i = 1; ; ++i){

current_obj = next_obj;

next_obj = (obj *)((char *)next_obj + n);

if(nobjs - 1 == i){

//最后一个节点的指针指向NULL

current_obj->free_list_link = 0;

break;

}else{

current_obj->free_list_link = next_obj;

}

}

return (result);

}

//从内存池中取出空间给free_list使用

template<bool threads, int inst>

char *__defaule_alloc_template<threads, inst>::chunk_alloc(size_t size, int &nobjs)

{

char *result;

size_t total_bytes = size * nobjs;//需要给free_list分配的空间大小

size_t bytes_left = end_free - start_free;//内存池剩余空间大小

//内存池的空间足够满足需求量

if(bytes_left >= total_bytes){

result = start_free;//result得到新的free_list的起始位置

start_free += total_bytes;

return result;

}

//内存池剩余空间不能够满足需求量,但是足够供应一个或一个以上的区块

else if(bytes_left >= size){

nobjs = bytes_left / size;

total_bytes = size * nobjs;

result = start_free;

start_free += total_bytes;

return result;

//一个区块都无法满足

}else{

size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);

//内存池还有一些零头,先分配给适当的free_list

if(bytes_left > 0){

obj * volatile * my_free_list = free_list + FREELIST_INDEX(bytes_left);

((obj *)start_free)->free_list_link = *my_free_list;

*my_free_list = (obj *)start_free;

}

//内存池一点零头都没有了,就配置heap空间

start_free = (char *)malloc(bytes_to_get);

//如果系统的heap空间不足,malloc()失败

if(0 == start_free){

int i;

obj * volatile * my_free_list, *p;

//遍历搜索看还有没有用的free_list吗,

for(i = size; i < __MAX_BYTES; i += __ALIGN){

my_free_list = free_list + FREELIST_INDEX[i];

p = *my_free_list;

//free_list有没有用的区块

if(0 != p){

*my_free_list = p->free_list_link;

start_free = (char *)p;

end_free = start_free + i;

return chunk_alloc(size,nobjs);

}

}

//到处没有内存可用则调用一级空间配置器

end_free = 0;

start_free = (char *)malloc_alloc::allocate(bytes_to_get);

}

heap_size += bytes_to_get;

end_free = start_free + bytes_to_get;

//递归调用自己为了修正nobjs

return chunk_alloc(size,nobjs);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: