C++的内存配置基本操作是::operator new(),内存释放的基本操作是::operator delete()。这两个全局函数相当于C的malloc()与free()函数。是的,SGI正是以malloc()与free()完成内存配置与释放。
考虑到小型区块所可能造成的内存碎片问题,SGI设计了双层级配置器,第一级配置器直接使用malloc()和free(),第二级配置器则视情况而定采用不同的策略:
当配置区块超过128bytes时,将之视为足够大,便调用第一级配置器;当配置区块小于128bytes时,将之视为过小,为了降低额外负担,便采用复杂的memory pool整理方式,而不再求助于第一级配置器。无论是第一级配置器还是第二级配置器都使用了一个simple_alloc接口。例如:
template<class T,class Alloc = alloc>//缺省使用alloc为配置器
class vector{
typedef simple_alloc<value_type,Alloc> data_allocator;
.......
void deallocate(){
data_allocator::deallocate(start,end_of_storage-start);
}
......
};
配置器关系图如下:
第一级配置器__malloc_alloc_template<0>
第一级配置器以malloc(),free(),realloc()等C函数执行实际的内存配置,释放,重配置等操作,并实现了C++new-handler的机制。
注意:SGI第一级配置器的allocate()和realloc()都是在调用malloc()和realloc()不成功后,调用oom_malloc()和oom_realloc()。后两者都有内循环,不断调用内存不足处理历程,期望在某次调用之后,获得足够的内存。
template<int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
void (* my_malloc_handler)();
void *result ;
for(;;)//调用一个内循环,不断的尝试释放、配置、再释放、再配置。
{
my_malloc_handler = __malloc_alloc_oom_handler ;
if(0 == my_malloc_handler){ __THROW_BAD_ALLOC ;}
(*my_malloc_handler)();//调用处理例程,企图释放内存
result = malloc(n);//再次尝试配置内存
if(result)
return result ;
}
}
}
第二级配置器__default_alloc_template<__NODE_ALLOCATOR_THREADS,0>
SGI第二级配置器的做法是:如果区块大于128bytes时,就移交给第一级配置器。当区块小于128bytes时,则以内存池(memory pool)管理,此法称为次层配置,每次配置一大块内存,并维护对应之自由链表。下次若再有相同大小的内存需求,就直接从自由链表中拨出。如果客户端释还小额区块,就由配置器回收到自由链表中。为了方便管理,SGI第二级配置器会主动将任何小额区块的内存需求量上调至8的倍数。并维护16个自由链表(free-lists),各自管理大小分别为:8,16,24,32.........120,128bytes的小额区块。