STL的第二级配置器
本文不考虑异常处理情况。
STL的第二级配置器是默认使用的配置器,第一级配置器只是简单的调用malloc(),free(),realloc()等函数,并没有真正意义上对内存进行管理
STL的第二级配置器相对较为复杂,利用了链表的形式管理16种内存大小不同的区块。由于链表的存在,当使用内存不再需要时,不是简单的释放(free()),而是将其回收到链表中,省去了反复释放和申请内存的开销。
代码如下:
1 #ifndef __H_DEFAULT 2 #define __H_DEFAULT 3 #include "__malloc_alloc_template.h" 4 5 enum {__ALIGN = 8}; // 小型区块的上调边界 6 enum {__MAX_BYTES = 128}; // 小型区块的上限 7 enum {__NFREELISTS = __MAX_BYTES / __ALIGN}; // free-lists 个数 8 9 10 template<bool threads, int inst> 11 class __defalut_alloc_template 12 { 13 private: 14 // ROUND_UP() 将bytes上调至8的倍数 15 static size_t ROUND_UP(size_t bytes) 16 { 17 return ((bytes) + __ALIGN - 1) & ~(__ALIGN - 1); 18 } 19 20 private: 21 union obj // free-lists 的节点构造 22 { 23 union obj* free_list_link; 24 char client_data[1]; 25 }; 26 27 private: 28 // 16个free-lists 29 static obj * volatile free_list[__NFREELISTS]; 30 // 以下函数根据区块大小,决定使用第n号free-list,n从0算起 31 static size_t FREELIST_INDEX(size_t bytes) 32 { 33 return (((bytes) + __ALIGN - 1)/__ALIGN -1); 34 } 35 36 // 返回一个大小为n的对象,并可能加入大小为n的其他区块到free list 37 static void* refill(size_t n); 38 static char* chunk_alloc(size_t size, int& nobjs); 39 40 // Chunk allocation state 41 static char* start_free; // 内存池的起始位置,只在chunk_alloc()中变化 42 static char* end_free; // 内存池的结束位置,只在chunk_alloc()中变化 43 static size_t heap_size; 44 45 public: 46 static void* allocate(size_t n) 47 { 48 // a pointer to a valatile pointer to obj 49 obj * volatile * my_free_list; 50 obj * result; 51 // 大于128就使用第一级配置器 52 if(n > (size_t) __MAX_BYTES) 53 { 54 return malloc_alloc::allocate(n); 55 } 56 57 // 寻找16个free list中适当的一个 58 my_free_list = free_list + FREELIST_INDEX(n); 59 result = *my_free_list; 60 if(result == 0) 61 { 62 // 没有找到可用的free list,准备重新填充free list 63 void* r = refill(ROUND_UP(n)); 64 return r; 65 } 66 *my_free_list = result->free_list_link; 67 return result; 68 } 69 70 public: 71 static void deallocate(void* p, size_t n) 72 { 73 obj* q = (obj *)p; 74 obj * volatile * my_free_list; 75 76 // 大于128就调用第一级配置器 77 if(n > (size_t)__MAX_BYTES) 78 { 79 malloc_alloc::deallocate(p, n); 80 return; 81 } 82 83 // 寻找对应的free list 84 my_free_list = free_list + FREELIST_INDEX(n); 85 // 调整free list,回收区块 86 q->free_list_link = *my_free_list; 87 *my_free_list = q; 88 } 89 90 static void* reallocate(void* p, size_t old_sz, size_t new_sz); 91 }; 92 93 // 以下是static data member 的定义与初值设定 94 template<bool threads, int inst> 95 char* __defalut_alloc_template<threads, inst>::start_free = 0; 96 97 template<bool threads, int inst> 98 char* __defalut_alloc_template<threads, inst>::end_free = 0; 99 100 template<bool threads, int inst> 101 size_t __defalut_alloc_template<threads, inst>::heap_size = 0; 102 103 template<bool threads, int inst> 104 typename __defalut_alloc_template<threads, inst>::obj * volatile 105 __defalut_alloc_template<threads, inst>::free_list[__NFREELISTS] = {0}; 106 107 108 template<bool threads, int inst> 109 void* __defalut_alloc_template<threads, inst>::refill(size_t n) 110 { 111 int nobjs = 20; 112 char* chunk = chunk_alloc(n, nobjs); 113 obj * volatile * my_free_list; 114 obj * result; 115 obj * current_obj, * next_obj; 116 int i; 117 118 // 如果只获得一个区块,这个区块就分配给调用者用,free list 无新节点 119 if(nobjs == 1) 120 return chunk; 121 // 否则准备调整free list,纳入新节点 122 my_free_list = free_list + FREELIST_INDEX(n); 123 124 // 以下在chunk空间内建立free list 125 result = (obj *)chunk; // 这一块返回给客端 126 // 以下引导free list 指向新配置的空间(取自内存池) 127 *my_free_list = next_obj = (obj *)(chunk + n); 128 // 以下将free list 串接起来 129 for(i = 1; ; i++) // 从1开始,因为第0个将返回给客端 130 { 131 current_obj = next_obj; 132 next_obj = (obj *)((char *)next_obj + n); 133 if(nobjs - 1 == i) 134 { 135 current_obj->free_list_link = 0; 136 break; 137 } else 138 { 139 current_obj->free_list_link = next_obj; 140 } 141 } 142 return result; 143 } 144 145 template<bool thread, int inst> 146 char* __defalut_alloc_template<thread, inst>:: 147 chunk_alloc(size_t size, int& nobjs) 148 { 149 char* result; 150 size_t total_bytes = size * nobjs; 151 size_t bytes_left = end_free - start_free; // 内存池剩余空间 152 153 if(bytes_left >= total_bytes) 154 { 155 // 内存池剩余空间完全满足需求 156 result = start_free; 157 start_free += total_bytes; 158 return result; 159 } else if(bytes_left >= size) 160 { 161 // 内存池剩余空间不能完全满足需求量,但足够提供一个(含)以上的区块 162 nobjs = bytes_left / size; 163 total_bytes = size * nobjs; 164 result = start_free; 165 start_free += total_bytes; 166 return result; 167 } else 168 { 169 // 内存池剩余空间连一个区块大小都无法提供 170 size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4); 171 // 以下试着让内存池中的残余零头还有利用价值 172 if(bytes_left > 0) 173 { 174 // 内存池内还有一些零头,先配给适当的free list 175 // 首先寻找适当的free list 176 obj * volatile * my_free_list = 177 free_list + FREELIST_INDEX(bytes_left); 178 // 调整free list,将内存池中的残余空间编入 179 ((obj *)start_free)->free_list_link = *my_free_list; 180 *my_free_list = (obj *)start_free; 181 } 182 183 // 配置heap空间,用来补充内存池 184 start_free = (char *)malloc(bytes_to_get); 185 if(0 == start_free) 186 { 187 // heap 空间不足,malloc()失败 188 int i; 189 obj * volatile * my_free_list, *p; 190 // 试着检视我们手上拥有的东西 191 // 以下搜寻适当的free list 192 // 所谓适当是指"尚有未用,且区块足够大"的free list 193 for(i = size; i < __MAX_BYTES; i += __ALIGN) 194 { 195 my_free_list = free_list + FREELIST_INDEX(size); 196 p = *my_free_list; 197 if(p != 0) 198 { 199 // 调整free list以释放未用区块 200 *my_free_list = p->free_list_link; 201 start_free = (char *)p; 202 end_free = start_free + i; 203 // 递归调用自己,修正nobjs 204 return chunk_alloc(size, nobjs); 205 } 206 } 207 end_free = 0; // 如果出现意外(山穷水尽,到处都没有内存用了) 208 // 调用第一配置器,看看out-of-memory机制能否尽力 209 start_free = (char *)malloc_alloc::allocate(bytes_to_get); 210 } 211 heap_size += bytes_to_get; 212 end_free = start_free + bytes_to_get; 213 // 递归调用自己,修正nobjs 214 return chunk_alloc(size, nobjs); 215 } 216 } 217 218 typedef __defalut_alloc_template<0,0> alloc; 219 220 221 #endif
浙公网安备 33010602011771号