union obj{
union obj * free_list_link;
char client_data[1];
};
static void * allocate(size_t n)
{
obj * __VOLATILE * my_free_list;
obj * __RESTRICT result;
// 如果大于__MAX_BYTES就调用第一级配置器
if (n > (size_t) __MAX_BYTES) {
return (malloc_alloc::allocate(n));
}
// 寻找free_list中适当的一个
my_free_list = free_list + FREELIST_INDEX(n);
// 1.这里表明my_free_list指向的值是实际分配的内存
result = *my_free_list;
if (result == 0) {
void *r = refill(ROUND_UP(n));
return r;
}
// 2.但这里又表明my_free_list指向的值是下一块空闲的obj的地址
*my_free_list = result -> free_list_link;
return (result);
};
我的理解
1.free_lists是一个指针数组,指向实际的内存
2.实际的内存的前4个字节是union结构,其中前4个字节指向下一个可用的block
3.返回实际的内存地址后,free_lists里面的指针更新为下一个内存地址
下面这张图来源于stl源码剖析
空间释放函数deallocate
static void deallocate(void* p, size_t n)
{
obj* q = (obj*)p;
obj* volatile* my_free_list;
if (n > (size_t)__MAX_BYTES)
{
malloc_alloc::deallocate(p, n);
return;
}
my_free_list = free_list + FREELIST_INDEX(n);
q->free_list_link = *my_free_list;
*my_free_list = q;
}
重新填充free_list,啥意思呢?就是没有可用区块的时候,需要重新分配一个
template<bool threads, int inst>
void* __default_alloc_template<threads, inst>::refill(size_t n)
{
int nobjs = 20;
char* chunk = chunck_alloc(n, nobjs);
obj* volatile *my_free_list;
obj* result;
obj* current_obj, *next_obj;
int i;
if (1 == nobjs) return(chunk);
my_free_list = free_list + FREELIST_INDEX(n);
result = (obj*)chunk;
*my_free_list = next_obj = (obj_*)(chunk + n);
for (int i = 1; ; i++)
{
current_obj = next_obj;
next_obj = (obj*)((char*)next_obj + n);
if (i == nobjs - 1)
{
current_obj->free_list_link = 0;
break;
}
else
{
current_obj -> free_list = next_obj;
}
}
return result;
}
内存池
template<bool threads, int& inst>
char __default_alloc_template<threads, inst>::
chunk_alloc(size_t size, int& nobjs)
{
char* result;
size_t total_bytes = size * 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 >= 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(head_size >> 4);
}
}