一,二级配置器的源代码
enum{_ALIGN = 8}; //小型区块的上调边界
enum{_MAX_BYTES = 128}; //小型区块的上界
enum{_NFREELISTS = _MAX_BYTES/_ALIGN}; //free-lists 个数
/**
* 第一个参数用于多线程环境,第二个参数完全没有派上用场
*/
template<bool threads, int inst>
class _default_alloc_template{
private:
//free list的节点
union obj{
union obj *free_list_link;
char client_data[1];
};
//16 个free-lists
static obj *volatile free_list[_NFREELISTS];
//返回一个大小为n的对象,并可能加入大小为n的其他区块到free-list中
static void *refill(size_t n);
//配置一大块空间,可容纳nobjs个大小为size的区块
static char *chunk_alloc(size_t size, int &nobjs);
//内存池起始位置,只在chunk_alloc()中变化
static char *start_free;
//内存池结束位置,只在chunk_alloc()中变化
static char *end_free;
public:
static void *allocate(size_t n);
static void deallocate(void *p, size_t n);
static void *reallocate(void *p, size_t old_sz, size_t new_sz);
};
/**
* 空间配置器
*
* 此函数首先判断区块的大小,大于128byte就调用一级配置器,小于128byte就检查对应的
* free-lists。如果free-lists内有可用的区块,就直接拿来使用,如果没有可用区块,就
* 把区块的大小上调至8的倍数,然后准备调用refill()准备为free-lists重新填充空间。
*/
template<bool threads, int inst>
static void *_default_alloc_template<threads, inst>::allocate(size_t n){
obj * volatile *my_free_list;
obj *result;
//大于128就调用第一级配置器
if(n > _MAX_BYTES){
return (malloc_alloc::allocate(n));
}
//寻找16个free-lists中适当的一个
my_free_list = free_list + FREELIST_INDEX(n);
result = *my_free_list;
if(result == 0){
//没有找到可用的区块,准备填充free-lists
void *r = refill(ROUND_UP(n));
return r;
}
//调整free-lists
*my_free_list = result->free_list_link;
return (result);
}
/**
* 空间释放器
*
* 此函数首先判断区块大小,大于128byte就调用第一级配置器,小于128byte就找出对应的
* free-lists,将区块回收。
*/
template<bool threads, int inst>
static void _default_alloc_template<threads, inst>::deallocate(void *p, size_t n){
obj * volatile *my_free_list;
obj *result;
//大于128byte就调用第一级配置器
if(n > (size_t)_MAX_BYTES){
malloc_alloc::deallocate(p, n);
return;
}
//寻找对应的feee-lists
my_free_list = free_list + FREELIST_INDEX(n);
//调整free-lists,回收区块
q->free_list_link = *my_free_list;
*my_free_list = q;
}
二,重新填充free-lists
二级配置器使用allocate()配置内存,当它发现free-lists中没有可用的区块时,就调用refill(),准备为free-lists重新填充空间。新的空间将取自内存池(经由chunk_alloc()完成),缺省取得20个新的节点(新区块),但万一内存池空间不够,获得的节点数可能小于20。
三,内存池
从内存池中取空间给free-lists使用,是chunk_alloc()函数的工作。chunk_alloc()函数以end_free - start_free来判断内存池的水量。如果水量充足,就直接调出20个区块返回给free-lists使用。如果水量不足以提供20个区块,但足够供应一个以上的区块,就拨出这不足20个区块的空间出去。如果内存池连一个区块空间都无法供应,此时便使用malloc()从heap中配置内存,为内存池注入源头活水以应付需求。新水量的大小为需求量的两倍,再加上一个随着配置次数增加而越来越大的附加量。万一heap空间不够用,malloc()失败,就调用第一级配置器,第一级配置器也是使用malloc()来配置内存,但它有out-of-memory处理机制,或许有机会可以释放掉其他内存拿来此处使用。如果可以就成功,否则抛出bad_alloc异常。