//二级空间配置器 __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[n];
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);
}
}