template<bool threads,int inst>
class __default_alloc_template
{
private:
enum {__ALIGN=8};
enum {__MAX_BYTES=128;};
enum {__NFREELISTS=__MAX_BYTES/__ALIGN};
/*struct obj
{
struct obj* free_list_link;
};*/
//结构体和下面,在此处中是效果一致的。本模板采取此数据结构
//相对好处,不是很明白
union obj
{
union obj* free_list_link;
char client_data[1];
};
//函数FREELIST_INDEX表示返回free_list[16]一个索引值
static size_t FREELIST_INDEX(size_t n)
{
return (((n)+__ALIGN-1)/__ALIGN-1);//返回对应的0-15的值。
}
//函数ROUND_UP出现,是为了对于空间大小是8,16,。。。128固定值,让n量化为其中某个值。
size_t ROUND_UP(size_t n)
{
//等效于return(((n-1)/__ALIGN+1)*__ALIGN);
return ((n+__ALIGN-1)&~(__ALIGN-1));
}
//函数chunk_alloc用于申请空间,想内存池
char* chunk_alloc(size_t n,size_t nobjs)
{
char * result;
size_t total_bytes=n*nobjs;//申请字节总数
size_t bytes_left=end_free-start_free;//表示内存池大小
if(bytes_left>=total_bytes)
{//表示完全满足分配要求
result=start_free;
start_free+=total_bytes;
return result;
}
else if(bytes_left>=n)
{//满足一个以上
result=start_free;
nobjs=bytes_left/n;//修正个数值
total_bytes=nobjs*n;
start_free+=total_bytes;
return result;
}
else
{//一个都满足不了了
if(bytes_left>0)
{//有内存;注意由于分配出来的都是8的倍数,则此时内存残余也是8的倍数
//收集残余内存
obj* volatile * my_free_list=free_list+FREELIST_INDEX(bytes_left);//适合残余bytes_left的空间收集
((obj*)start_free)->free_list_link=*my_free_list;
*my_free_list=(obj*)start_free;
}
//收集完本池中的残余空间后,则重新申请空间作为内存池。
//针对要求空间total_bytes,进行分配预留更多的,且考虑附加量,与已经申请了多少堆有关。
size_t bytes_to_get=2*total_bytes+ROUND_UP(heap_size>>4);
start_free=(char *)malloc(bytes_to_get);
if(start_free==0)
{//申请内存空间失败
//首先检测比分配空间更大的空间表是否有空闲内存。
obj *volatile*my_free_list,*p;//注意此处*p是obj *p
for(i=n;i<=__MAX_BYTES;i+=__ALIGN)
{
my_free_list=free_list+FREELIST_INDEX(i);
p=*my_free_list;
if(0!=p)
{//表示i的空间大小有空闲,则将其空间从中删除,作为内存池
*my_free_list=*my_free_list->free_list_link;
start_free=(char*)p;
end_free=(char*)p+i;
chunk_alloc(n,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;
return chunk_alloc(n,nobjs);//已经分配到空间了,内存池重新注满水了,下一步就是类似前面的返回所需空间了
}
}
//函数refill重新分配固定空间个数
void* refill(size_t n)
{
//默认大小空间数是20;
int nobjs=20;
//向内存池中申请空间,以提供给客端空间申请要求
char *chunk=chunk_alloc(n,nobjs);//nobjs表示希望的个数,如果实际内存池不够,则会修改该值。
obj * result,*current_obj,*next_obj;
obj* volatile *my_free_list;
if(nobjs==1) return(chunk);//此处注意,它表示申请不到20个空间,只能是一个,char*转为void*。
my_free_list=free_list+FREELIST_INDEX(n);//由于不止一个,则就需要修改空间链表指针。
result=(obj*)chunk;//char*转为obj*
next_obj=(obj*)(chunk+n);//char*转为obj*
*my_free_list=next_obj;//表示所指空间链表首地址
for(i=1;;i++)
{
current_obj=next_obj;
next_obj=(obj*)((char*)next_obj+n);//obj* 转为char*;char*转为obj*
if(nobjs-1==i)//表示分配了nobjs个但是有个被用了,故而就只有这么多个
{
current_obj->free_list_link=0;//最后一个设置为0;则当它被用了后,则原表中的指针只能值为0;
break;
}
else
current_obj->free_list_link=next_obj;
}
return result; //obj*转为void*
}
static obj* volatile free_list[__NFREELISTS];
static char* end_free;
static char* start_free;
static size_t heap_size;
public:
static void *allocate(size_t n)
{
//指针值,该指针指向一个obj*值,且是不可优化的,也就是free_list[16]值不可优化。
obj * volatile *my_free_list;
//分配空间结果位置---返回时其实质也就转为了void*指针类型了。被用时又转为相应的类型
obj * result;
if(n>(size_t)__MAX_BYTES)
return (malloc_alloc::allocate(n));
my_free_list=free_list+FREELIST_INDEX;//根据待分配空间大小给出指针所指free_list的值
//free_list数组所指是空间链表,链表如果没有空间则指向的是0值,否则是空间首地址。
result=*my_free_list;//所指空间处
if(0==result)
{
//需要申请空间配置扩展该固定字段空间。
void *p=refill(ROUND_UP(n));//表示分配后空间,返回一个被用,ROUND_UP是表示n上调其固定值。
return p;
}
//如果成功被分配出去了,则下面就得调整本链表空间。
*my_free_list=result->free_list_link;//只需要修改所指所指首地址,没有空间则指为0
return result;//obj*转为void*
}
static void deallocate(void *p ,size_t n)
{
if(n>__MAX_BYTES)
return (malloc_alloc::deallocate(p,n));
obj* volatile * my_free_list=free_list+FREELIST_INDEX;
((obj*)p)->free_list_link=*my_free_list;
*my_free_list=(obj*)p;
}
static void *reallocate(void *p ,size_t old_sz,size_t new_sz)
{
void * result;
size_t copy_sz;
//对于老的内存,新的内存都大于128则交给一级处理
if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES)
return(realloc(p, new_sz));
//对于新旧内存上调后一致,则不需要重新分配空间
if (ROUND_UP(old_sz) == ROUND_UP(new_sz))
return(p);
//否则先利用分配空间,分出来
result = allocate(new_sz);
//复制其中空间内容
copy_sz = new_sz > old_sz? old_sz : new_sz;//取空间小的;这里有可能是全拷贝,有富裕空间;也有可能是截断拷贝
memcpy(result, p, copy_sz);//函数用于复制在#include <string.h>;C语言库中
//复制完后,进行收回原来的内存空间。
deallocate(p, old_sz);
return(result);
}
};