SGI STL分为两级空间配置器:
以下代码展现了alloc中内存的调度
//alloc.h #ifndef ALLOC_H #define ALLOC_H #if 0 # include <new> # define __THROW_BAD_ALLOC throw bad_alloc #elif !defined(__THROW_BAD_ALLOC) # include <iostream> # define __THROW_BAD_ALLOC cerr << "out of memory" << endl; exit(1) #endif //第一级配置器 //非型别参数inst没有起到作用 template <int inst> class __malloc_alloc_template { private: //以下函数用来处理内存不足的情况 oom 即 out of memory static void* oom_malloc(size_t); static void* oom_realloc(void*, size_t); static void (* __malloc_alloc_oom_handler)(); public: static void* allocate(size_t n) { void *result = malloc(n); //第一级配置器直接使用malloc() //无法分配时使用oom_malloc() if(result == 0) { result = oom_malloc(n); } return result; } static void* dellocate(void *p, size_t) { free(p); //第一级配置器使用free() } static void* reallocate(void *p, size_t, size_t new_sz) { void *result = realloc(p, new_sz); if(result == 0) { result = oom_realloc(p, new_sz); } return result; } //仿真c++的set_new_handler()机制,指定自己的out_memory_handler //set_malloc_handler函数 函数参数void (*f)() // 返回类型void (*f)() static void (*set_malloc_handler(void (*f)()))() { void (*old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = f; return old; } }; //out_of_memory handler初值设为0 template <int inst> void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0; template <int inst> void* __malloc_alloc_template<inst>::oom_malloc(size_t n) { void (*my_malloc_handler)(); void *result; for(;;) { //不断地尝试释放,配置,再释放,再配置^ my_alloc_handler = __malloc_alloc_oom_handler; if(my_alloc_handler == 0) { __THROW_BAD_ALLOC; } (*my_malloc_handler)(); //调用处理例程,企图释放内存 result = malloc(n); if(result != 0) { return result; } } } //与oom_malloc类似 template <int inst> void* __malloc_alloc_template<inst>::oom_realloc(void *p, size_t n) { void (*my_malloc_handler)(); void *result; for(;;) { my_malloc_handler = __malloc_alloc_oom_handler; if(my_malloc_handler = 0) { __THROW_BAD_ALLOC; } (*my_malloc_handler)(); result = realloc(p, n); if(result != 0) { return result; } } } typedef __malloc_alloc_template<0> malloc_alloc; //end(第一级配置器) //第二级配置器 enum {__ALIGN = 8}; //小型区块的上调边界 enum {__MAX_BYTES = 128}; //小型区块的上限 enum {__NFREELISTS = __MAX_BYTES/__ALIGN}; //free_lists的个数 template <bool threads, int inst> class __default_alloc_template { private: //ROUND_UP()将bytes上调至8的倍数 static size_t ROUND_UP(size_t bytes) { return (((bytes) + __ALIGN-1) & ~(__ALIGN - 1)); } private: //free_lists的节点构造 union obj { union obj *free_list_link; char client_data[1]; }; private: //16个free_lists static obj * volatile free_list[__NFREELISTS]; //此函数可根据区块的大小,决定使用第n号free_list, n从0开始 static size_t FREELIST_INDEX(size_t bytes) { return (((bytes) + __ALLIGN-1)/__ALIGN - 1); } //返回一个大小为n的对象,并可能加入大小为n的其它区块到free_list static void* refill(size_t n); //配置一大块空间,可容纳nobjs个大小为size的区域 //如果配置nobjs个区块有所不便,nobjs可能会降低 static char* chunk_alloc(size_t size, int &nobjs); //块的状态 static char *start_free; //内存池起始位置,只在chunk_alloc()中变化 static char *end_free; //内存池结束位置,只在chunk_alloc()中变化 static size_t heap_size; 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); } //找到16个free lists中适当的一个 my_free_list = free_list + FREELIST_INDEX[n]; result = *my_free_list; if(result == 0) { //没有找到可用的free_list,准备重新填充free lists void *r = refill(ROUND_UP(n)); return r; } //调整free_list *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; //大于128则调用第一级配置器 if(n > 128) { malloc_alloc::dellocate(p, n); return; } //寻找对应的free list my_free_list = free_list + FREELIST_INDEX(n); //调整free_list,将q安插在区块头部 q->free_list_link = *my_free_list; *my_free_list = q; } static void* reallocate(void *p, size_t old_sz, size_t new_sz); }; //设定初值 template <bool threads, int inst> char * __default_alloc_template<threads, inst>::start_free = 0; template <bool threads, int inst> char * __default_alloc_template<threads, inst>::end_free = 0; template <bool threads, int inst> char * __default_alloc_template<threads, inst>::heap_size = 0; template <bool threads, int inst> typename __default_alloc_template<threads, inst>::obj * volatile __default_alloc_template<threads, inst>::free_list[__NFREELISTS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //返回一个大小为n的对象,并且有时候会为适当的free list增加节点 //n已经被适当上调为8的倍数 template <bool threads, int inst> void* __default_alloc_template<threads, inst>::refill(size_t n) { int nobjs = 20; //调用chunk_alloc(),尝试取得nobjs个区块作为free list的新节点 char *chunk = chunk_alloc(n, nobjs); obj * volatile * my_free_list; obj *result; obj *current_obj, *next_obj; int i; //如果只获得一个区块,将这个区块分配给调用者,free list无新节点 if(nobjs == 1) { return chunk; } //否则调整free list,纳入新节点 my_free_list = free_list + FREELIST_INDEX(n); //以下在得到的块中建立free list result = (obj*)chunk; //这一块返回给调用者 *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) { current_obj->free_list_link = 0; break; } else { current_obj->free_list_link = next_obj; } } return result; } //内存池 //nobjs是引用调用的 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(heap_size >> 4); if(bytes_left > 0) { //内存池中还有一些零头,先配给适当的free list //寻找合适的free list obj * volatile * my_free_list = free_list + FREELIST_INDEX(bytes_left); //调整free list,将内存池中的残余空间编入 ((obj*)start_free)->free_list_link = *my_free_list; *my_free_list = (obj*)start_free; } //配置heap空间,用来补充内存池 start_free = (char*)malloc(bytes_to_get); if(start_free == 0) { //heap空间不足,malloc()失败 int i; obj * volatile * my_free_list, *p; for(i = size; i < __MAX_BYTES; i += __ALIGN) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if(p != 0) { //free_list内尚有未用区块 //调整free list 以释放未用区块 *my_free_list = p->free_list_link; start_free = (char*)p; end_free = start_free + i; //递归调用自己,为了修正nobjs return chunk_alloc(size, nobjs); } } end_free = 0; //如果出现意外(没有内存可用了) //调用第一级配置器,看看out_of_memory机制能否起作用,会抛出异常 //或内存不足的情况得到改善 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); } } #endif