static void *allocate(size_t n) { void *result = malloc(n); if (NULL == result) result = oom_malloc(n); return result; }
deallocate對free函數簡單封裝 :html
static void deallocate(void *p, size_t) { free(p); }
oom_malloc調用外部提供的malloc失敗處理函數,而後從新試着再次調用malloc。重複執行此過程,直到malloc成功爲止 : git
template <int inst> void* __malloc_alloc<inst>::oom_malloc(size_t n) { void (*my_malloc_handler)(); void *result; for (;;) { my_malloc_handler = malloc_alloc_oom_handler; if (NULL == my_malloc_handler) __THROW_BAD_ALLOC; (*my_malloc_handler)(); result = malloc(n); if (result) return result; } }
第二級空間配置器github
//自由鏈表 union obj { union obj *free_list_link; char data[1]; }; //自由鏈表數組 static obj *volatile free_list[__NFREELISTS];
template <bool threads> void *__default_alloc<threads>::allocate(size_t n) { obj *volatile *my_free_list; obj *result; if (n > (size_t)__MAX_BYTES) //調用第一級配置器 return malloc_alloc::allocate(n); my_free_list = free_list + FREELIST_INDEX(n); result = *my_free_list; if (result == NULL) { //第n號鏈表無內存塊,則準備從新填充該鏈表 void *r = refill(ROUND_UP(n)); return r; } *my_free_list = result->free_list_link; return result; }
template <bool threads> void *__default_alloc<threads>::refill(size_t n) { int nobjs = __NOBJS; char *chunk = chunk_alloc(n, nobjs); //從內存池獲取內存 if (nobjs == 1) //只能分配一塊,則直接返回給調用者 return chunk; obj *volatile *my_free_list; obj *result, *next_obj, *current_obj; result = (obj *)chunk; my_free_list = free_list + FREELIST_INDEX(n); *my_free_list = next_obj = (obj *)(chunk + n); for (int i = 1; i < nobjs - 1; i++) //將剩下的區塊添加進鏈表 { current_obj = next_obj; next_obj = (obj *)(char *)(next_obj + n); current_obj->free_list_link = next_obj; } //最後一塊 current_obj = next_obj; current_obj->free_list_link = NULL; return result; }
if (size_left >= total_size) //內存池剩餘空間知足需求 { result = start_free; start_free += total_size; return result; }
若內存池大小沒法知足20個內存節點的大小,但至少知足1個內存節點,則直接返回相應的內存節點大小的內存塊給refill;數組
else if (size_left >= size) //剩餘空間不能所有知足,但至少知足一塊 { nobjs = size_left / size; result = start_free; start_free += nobjs * size; return result;
若內存池連1個內存節點大小的內存塊都沒法提供,則chunk_alloc函數會將內存池中那一點點的內存大小分配給其餘合適的鏈表,而後去調用malloc函數分配的內存大小爲所需的兩倍。若malloc成功,則返回相應的內存大小給refill;若malloc失敗,會先搜尋其餘鏈表的可用的內存塊,添加到內存池,而後遞歸調用chunk_alloc函數來分配內存,若其餘鏈表也無內存塊可用,則只能調用第一級空間配置器,由於第一級空間配置器有malloc失敗的出錯處理函數,最終的但願只能寄託在那裏了。函數
template <bool threads> char *__default_alloc<threads>::chunk_alloc(size_t size, int& nobjs) { size_t total_size = size * nobjs; char *result; size_t size_left = end_free - start_free; if (size_left >= total_size) //內存池剩餘空間知足需求 { result = start_free; start_free += total_size; return result; } else if (size_left >= size) //剩餘空間不能所有知足,但至少知足一塊 { nobjs = size_left / size; result = start_free; start_free += nobjs * size; return result; } else //連一個區塊都沒法知足 { if (size_left > 0) //將殘餘內存分配給其餘合適的鏈表 { obj *volatile *my_free_list = free_list + FREELIST_INDEX(size_left); ((obj *)start_free)->free_list_link = *my_free_list; //在頭部插入 *my_free_list = (obj *)start_free; } size_t bytes_to_get = 2 * total_size + ROUND_UP(heap_size >> 4); start_free = (char *)malloc(bytes_to_get); if (start_free == NULL) //堆空間不足 { int i; obj *volatile *my_free_list; obj *p; for (i = size; i < __MAX_BYTES; i++) { my_free_list = free_list + FREELIST_INDEX(i); p = *my_free_list; if (p != NULL) { *my_free_list = p->free_list_link; start_free = (char *)p; end_free = start_free + i; return chunk_alloc(size, nobjs); } } end_free = NULL; //調用第一級配置器 start_free = (char *)malloc_alloc::allocate(bytes_to_get); } heap_size += bytes_to_get; end_free = start_free + heap_size; return chunk_alloc(size, nobjs); } }
void __default_alloc<threads>::deallocate(void *p, size_t n) { //大於__MAX_BYTES,則釋放該內存 if (n > (size_t)__MAX_BYTES) malloc_alloc::deallocate(p, n); obj *q = (obj *)p; obj *volatile *my_free_list; my_free_list = free_list + FREELIST_INDEX(n); //小於__MAX_BYTES,則回收區塊,並未釋放 q->free_list_link = *my_free_list; *my_free_list = q; }
內存對外接口spa
STL對外提供了一個simple_alloc類,該類提供統一的接口:allocate函數、deallocate函數,使得外部無需關心使用的是幾級內存配置器。另外simple_alloc類將外部所需的對象個數轉換爲字節。以下。指針
template <typename T, typename Alloc> class simple_alloc { public: static T *allocate(size_t n) // 個數 { return n == 0 ? 0 : (T*)Alloc::allocate(n * sizeof(T)); // 將個數轉換爲字節 } static T *allocate(void) { return (T*)Alloc::allocate(sizeof(T)); } static void deallocate(T *p, size_t n) // 個數 { if (n != 0) Alloc::deallocate(p, n * sizeof(T)); } static void deallocate(T *p) { Alloc::deallocate(p, sizeof(T)); } };