1 .
2 #ifndef MEMORYPOOL_H
3 #define MEMORYPOOL_H
4 5 #include <stdio.h>
6 #include <assert.h>
7 8 using namespace std;
9 10 class MemoryPool
11 {
12 private:
13 14 // Really we should use static const int x = N 15 // instead of enum { x = N }, but few compilers accept the former. 16 enum {__ALIGN =
8};
// 小型区块的上调边界,即小型内存块每次上调8byte 17 enum {__MAX_BYTES =
128};
// 小型区块的上界 18 enum {__NFREELISTS = __MAX_BYTES/__ALIGN};
// free-lists的个数,为:16,每个free-list管理不同大小内存块的配置 19 20 // 将请求的内存大小上调整为8byte的倍数,比如8byte, 16byte, 24byte, 32byte 21 static size_t ROUND_UP(size_t bytes)
22 {
23 return (((bytes) + __ALIGN-
1) & ~(__ALIGN -
1));
24 }
25 26 union obj
27 {
28 union obj* free_list_link;
// 下一个区块的内存地址,如果为NULL,则表示无可用区块 29 char client_data[
1];
// 内存区块的起始地址 30 };
31 32 private:
33 static obj *free_list[__NFREELISTS];
// __NFREELISTS = 16 34 /* 35 free_list[0] --------> 8 byte(free_list[0]管理8bye区块的配置) 36 free_list[1] --------> 16 byte 37 free_list[2] --------> 24 byte 38 free_list[3] --------> 32 byte 39 ... ... 40 free_list[15] -------> 128 byte 41 */ 42 43 // 根据区块大小,决定使用第n号的free_list。n = [0, 15]开始 44 static size_t FREELIST_INDEX(size_t bytes)
45 {
46 return (((bytes) + __ALIGN-
1)/__ALIGN -
1);
47 }
48 49 // Returns an object of size n, and optionally adds to size n free list. 50 static void *refill(size_t n);
51 52 // 配置一大块空间,可容纳nobjs个大小为size的区块 53 // 如果配置nobjs个区块有所不便,nobjs可能会降低 54 static char *chunk_alloc(size_t size,
int &nobjs);
55 56 // Chunk allocation state. 57 static char *start_free;
// 内存池起始位置 58 static char *end_free;
// 内存池结束位置 59 static size_t heap_size;
// 内存池的大小 60 61 public:
62 63 // 公开接口,内存分配函数 64 static void* allocate(size_t n)
65 {
66 obj** my_free_list = NULL;
67 obj* result = NULL;
68 69 // 如果待分配的内存字节数大于128byte,就调用C标准库函数malloc 70 if (n > (size_t) __MAX_BYTES)
71 {
72 return malloc(n);
73 }
74 75 // 调整my_free_lisyt,从这里取用户请求的区块 76 my_free_list = free_list + FREELIST_INDEX(n);
77 78 79 result = *my_free_list;
// 欲返回给客户端的区块 80 81 if (result ==
0)
// 没有区块了 82 {
83 void *r = refill(ROUND_UP(n));
84 85 return r;
86 }
87 88 *my_free_list = result->free_list_link;
// 调整链表指针,使其指向下一个有效区块 89 90 return result;
91 };
92 93 94 // 归还区块 95 static void deallocate(
void *p, size_t n)
96 {
97 assert(p != NULL);
98 99 obj* q = (obj *)p;
100 obj** my_free_list = NULL;
101 102 // 大于128byte就调用第一级内存配置器 103 if (n > (size_t) __MAX_BYTES)
104 {
105 free(p) ;
106 }
107 108 // 寻找对应的free_list 109 my_free_list = free_list + FREELIST_INDEX(n);
110 111 // 调整free_lis,回收内存 112 q -> free_list_link = *my_free_list;
113 *my_free_list = q;
114 }
115 116 static void * reallocate(
void *p, size_t old_sz, size_t new_sz);
117 118 } ;
119 120 121 /* We allocate memory in large chunks in order to avoid fragmenting */ 122 /* the malloc heap too much. */ 123 /* We assume that size is properly aligned. */ 124 /* We hold the allocation lock. */ 125 126 // 假设size已经上调至8的倍数 127 // 注意nobjs是passed by reference,是输入输出参数 128 char* MemoryPool::chunk_alloc(size_t size,
int& nobjs)
129 {
130 char* result = NULL;
131 132 size_t total_bytes = size * nobjs;
// 请求分配内存块的总大小 133 size_t bytes_left = end_free - start_free;
// 内存池剩余空间的大小 134 135 if (bytes_left >= total_bytes)
// 内存池剩余空间满足要求量 136 {
137 result = start_free;
138 start_free += total_bytes;
139 140 return result;
141 }
142 else if (bytes_left >= size)
// 内存池剩余空间不能完全满足需求量,但足够供应一个(含)以上的区块 143 {
144 nobjs = bytes_left/size;
// 计算内存池剩余空间足够配置的区块数目 145 total_bytes = size * nobjs;
146 147 result = start_free;
148 start_free += total_bytes;
149 150 return result;
151 }
152 else // 内存池剩余空间连一个区块都无法提供 153 {
154 // bytes_to_get为内存池向malloc请求的内存总量 155 size_t bytes_to_get =
2 * total_bytes + ROUND_UP(heap_size >>
4);
156 157 // Try to make use of the left-over piece. 158 if (bytes_left >
0)
159 {
160 obj** my_free_list = free_list + FREELIST_INDEX(bytes_left);
161 162 ((obj *)start_free) -> free_list_link = *my_free_list;
163 *my_free_list = (obj *)start_free;
164 }
165 166 // 调用malloc分配堆空间,用于补充内存池 167 start_free = (
char *)malloc(bytes_to_get);
168 if (
0 == start_free)
// heap空间已满,malloc分配失败 169 {
170 int i;
171 obj ** my_free_list, *p;
172 173 // 遍历free_list数组,试图通过释放区块达到内存配置需求 174 for (i = size; i <= __MAX_BYTES; i += __ALIGN)
175 {
176 my_free_list = free_list + FREELIST_INDEX(i);
177 p = *my_free_list;
178 179 if (
0 != p)
180 {
181 *my_free_list = p -> free_list_link;
182 start_free = (
char *)p;
183 end_free = start_free + i;
184 185 return chunk_alloc(size, nobjs);
186 // Any leftover piece will eventually make it to the 187 // right free list. 188 }
189 }
190 191 end_free =
0;
// In case of exception. 192 193 // 调用第一级内存配置器,看看out-of-memory机制能否尽点力 194 195 // This should either throw an 196 // exception or remedy the situation. Thus we assume it 197 // succeeded. 198 }
199 200 heap_size += bytes_to_get;
201 end_free = start_free + bytes_to_get;
202 203 return chunk_alloc(size, nobjs);
204 }
205 206 }
207 208 209 /* Returns an object of size n, and optionally adds to size n free list. */ 210 /* We assume that n is properly aligned. */ 211 /* We hold the allocation lock. */ 212 void* MemoryPool::refill(size_t n)
213 {
214 int nobjs =
20;
215 216 // 注意nobjs是输入输出参数,passed by reference。 217 char* chunk = chunk_alloc(n, nobjs);
218 219 obj* * my_free_list = NULL;
220 obj* result = NULL;
221 obj* current_obj = NULL;
222 obj* next_obj = NULL;
223 int i;
224 225 // 如果chunk_alloc只获得了一个区块,这个区块就直接返回给调用者,free_list无新结点 226 if (
1 == nobjs)
227 {
228 return chunk;
229 }
230 231 // 调整free_list,纳入新结点 232 my_free_list = free_list + FREELIST_INDEX(n);
233 234 result = (obj*)chunk;
// 这一块返回给调用者(客户端) 235 236 237 // 用chunk_alloc分配而来的大量区块配置对应大小之free_list 238 *my_free_list = next_obj = (obj *)(chunk + n);
239 240 for (i =
1; ; i++)
241 {
242 current_obj = next_obj;
243 next_obj = (obj *)((
char *)next_obj + n);
244 245 if (nobjs -
1 == i)
246 {
247 current_obj -> free_list_link = NULL;
248 break;
249 }
250 else 251 {
252 current_obj -> free_list_link = next_obj;
253 }
254 }
255 256 return result;
257 }
258 259 // 重新配置内存,p指向原有的区块,old_sz为原有区块的大小,new_sz为新区块的大小 260 void* MemoryPool::reallocate(
void *p, size_t old_sz, size_t new_sz)
261 {
262 void* result = NULL;
263 size_t copy_sz =
0;
264 265 if (old_sz > (size_t) __MAX_BYTES && new_sz > (size_t) __MAX_BYTES)
266 {
267 return realloc(p, new_sz);
268 }
269 270 if (ROUND_UP(old_sz) == ROUND_UP(new_sz))
271 {
272 return p;
273 }
274 275 result = allocate(new_sz);
276 copy_sz = new_sz > old_sz? old_sz : new_sz;
277 278 memcpy(result, p, copy_sz);
279 280 deallocate(p, old_sz);
281 282 return result;
283 }
284 285 // 静态成员变量初始化 286 char* MemoryPool::start_free =
0;
287 288 char* MemoryPool::end_free =
0;
289 290 size_t MemoryPool::heap_size =
0;
291 292 MemoryPool::obj* MemoryPool::free_list[MemoryPool::__NFREELISTS]
293 = {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, };
294 295 #endif 296