-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmm.c
365 lines (302 loc) · 10.6 KB
/
mm.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/*
* Explicit free lists
*
* Coalescing policy:
* Deferred coalescing
* Coalesce as you free the blocks
*
* Placement policy:
* segregated free lists
* Maintain list(s) of free blocks, not all blocks
* need to store forward/back pointers, not just sizes
*
* Track only free blocks, so we can use payload area
* internal fragmentation in this way will be small
*/
#include "mm.h"
#include <string.h>
#include "memlib.h"
team_t team = {
/* Team name */
"Explicit free lists",
/* First member's full name */
"尹绍沣",
/* First member's student ID */
"2022012760",
/* Second member's full name (leave blank if none) */
"",
/* Second member's student ID (leave blank if none) */
""};
#define MIN_SIZE (4 * W_SIZE)
#define ALIGNMENT D_SIZE
#define ALIGN(size) (((size) + (ALIGNMENT - 1)) & ~(ALIGNMENT - 1))
/* MACROS */
#define W_SIZE (sizeof(size_t))
#define D_SIZE (2 * W_SIZE)
/* UTILS */
//p为指针
#define DEREF(p) (*(size_t *)(p))
#define PACK(size, alloc) ((size) | (alloc))
#define PUT(p, val) (*(size_t *)(p) = (val))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/* BLOCK */
//hp指向header
//bp指向真正分配的内存
/* READ */
#define BLOCK_SIZE(hp) (DEREF(hp) & ~7)
#define ALLOCATED(hp) (DEREF(hp) & 1)
#define PAYLOAD(hp) ((size_t *)(hp) + 1)
#define FOOTER_P(hp) ((char *)(hp) + BLOCK_SIZE(hp) - W_SIZE)
#define HEADER_P(bp) ((size_t *)(bp) - 1)
#define PREV_ALLOCATED(hp) (DEREF(hp) & 2)
#define PREV_HEADER_P(hp) ((char *)(hp) - *((size_t *)(hp)-1))
#define NEXT_HEADER_P(hp) ((char *)(hp) + BLOCK_SIZE(hp))
#define LIST_PREV(hp) (*((void **)(hp) + 1))
#define LIST_NEXT(hp) (*((void **)(hp) + 2))
/* WRITE */
#define MARK_ALLOCATED(hp) (DEREF(hp) |= 1)
#define MARK_PREV_ALLOCATED(hp) (DEREF(hp) |= 2)
#define MARK_FREE(hp) (DEREF(hp) &= ~1)
#define CLEAR_PREV_ALLOCATED(hp) (DEREF(hp) &= ~2)
#define ENLARGE(hp, size) (DEREF(hp) += (size))
/* LIST */
#define MIN_POWER 4
#define MAX_POWER 18
#define SEG_LEN (MAX_POWER - MIN_POWER + 1)
#define LOG2(size) (8 * sizeof(long long) - __builtin_clzll((size)-1))
#define INDEX(k) ((k) < MAX_POWER ? (k)-MIN_POWER : MAX_POWER - MIN_POWER)
#define ROOT(k) ((size_t *)mem_heap_lo() + INDEX(k) * 2 - 1)
/* CONST */
#define HIGH 96
#define MIN_EXPAND_SIZE 2048
/* UTIL FUNCTIONS */
// 将hp从对应的free list中移除
static void list_remove(void *hp);
// 将hp插入到对应的free list中
static void list_insert(void *hp);
// 合并相邻的空闲块,并将合并后的块插入到对应的free list中
static void *coalesce(void *hp);
// 扩展堆空间大小,返回扩展后的块的指针
static void *extend(size_t size);
// 将hp分割成大小为size的块,higher表示是否使用高地址部分
static void *split(void *hp, size_t size, int higher);
int mm_init(void) {
size_t end = ALIGN((size_t)mem_heap_lo() + (SEG_LEN * 2 + 1) * W_SIZE);
if (mem_sbrk(end - (size_t)mem_heap_lo()) == (void *)-1)
return -1;
// 初始化每个列表的头
int k = MIN_POWER;
while (k <= MAX_POWER) {
void *root = ROOT(k);
LIST_NEXT(root) = root;
LIST_PREV(root) = root;
++k;
}
//表示列表头的结束
DEREF(end - W_SIZE) = 3;
return 0;
}
void *mm_malloc(size_t size) {
//malloc的块只用保留header,故block_size为(size + W_SIZE)
size_t block_size = MAX(ALIGN(size + W_SIZE), MIN_SIZE);
void *hp;
int found = 0;
// 寻找合适的列表
// 在这里不进行collapse
for (int k = MIN(LOG2(block_size), MAX_POWER); k <= MAX_POWER && !found; ++k) {
void *root = ROOT(k);
hp = LIST_NEXT(root);
while (hp != root) {
if (BLOCK_SIZE(hp) >= block_size) {
list_remove(hp);
found = 1;
break;
}
hp = LIST_NEXT(hp);
}
}
// 如果没有找到合适的块,则扩展堆空间
if (!found) {
size_t extend_size = block_size;
size_t *epilogue = (size_t *)((char *)mem_heap_hi() - W_SIZE + 1);
if ((*epilogue & 2) == 0)
extend_size -= *(epilogue - 1);
hp = extend(extend_size);
if (hp == NULL)
return NULL;
}
// 设置分配标记
MARK_ALLOCATED(hp);
MARK_PREV_ALLOCATED(NEXT_HEADER_P(hp));
// 小的块使用低地址部分,大的块使用高地址部分
return PAYLOAD(split(hp, block_size, block_size > HIGH));
}
void mm_free(void *ptr) {
if (ptr == NULL)
return;
// coalesce会在内部处理分配标记
void *hp = coalesce(HEADER_P(ptr));
CLEAR_PREV_ALLOCATED(NEXT_HEADER_P(hp));
}
void *mm_realloc(void *ptr, size_t size) {
if (size == 0) {
mm_free(ptr);
return NULL;
}
if (ptr == NULL)
return mm_malloc(size);
//malloc的块只用保留header,故block_size为(size + W_SIZE)
size_t required_size = MAX(ALIGN(size + W_SIZE), MIN_SIZE);
//寻找此块内存对应block的header pointer
void *hp = HEADER_P(ptr);
size_t coalesced_size = BLOCK_SIZE(hp);
if(coalesced_size < required_size){
while (1) {
//物理上的下一个块
void *next = NEXT_HEADER_P(hp);
if (!ALLOCATED(next)) {
coalesced_size += BLOCK_SIZE(next);
list_remove(next);
}
//和下一块合并来装载
if (coalesced_size >= required_size) {
MARK_PREV_ALLOCATED(NEXT_HEADER_P(next));
ENLARGE(hp, BLOCK_SIZE(next));
break;
}
void *oldhp = hp;
//物理上的上一个块
if (!PREV_ALLOCATED(hp)) {
hp = PREV_HEADER_P(hp);
coalesced_size += BLOCK_SIZE(hp);
list_remove(hp);
}
//和前后两块合并来装载
if (coalesced_size >= required_size) {
PUT(hp, PACK(coalesced_size, PREV_ALLOCATED(hp) | 1));
MARK_PREV_ALLOCATED(NEXT_HEADER_P(hp));
memmove(PAYLOAD(hp), PAYLOAD(oldhp), BLOCK_SIZE(oldhp) - W_SIZE);
break;
}
//空间到现在还是不够
PUT(hp, PACK(coalesced_size, PREV_ALLOCATED(hp) | 1));
MARK_PREV_ALLOCATED(NEXT_HEADER_P(hp));
// malloc 同时复制数据
void *bp = mm_malloc(size);
if (bp == NULL)
return NULL;
memcpy(bp, PAYLOAD(oldhp), BLOCK_SIZE(oldhp) - W_SIZE);
//释放原来的块
MARK_FREE(hp);
PUT(FOOTER_P(hp), coalesced_size);
CLEAR_PREV_ALLOCATED(NEXT_HEADER_P(hp));
list_insert(hp);
return bp;
}
}
//空间够用的情况也会在此处理
size_t free_size = BLOCK_SIZE(hp) - required_size;
if (free_size >= MIN_SIZE) {
PUT(hp, PACK(required_size, PREV_ALLOCATED(hp) | 1));
void *hq = (char *)hp + required_size;
//hq为新块的header
PUT(hq, PACK(free_size, 2));
PUT(FOOTER_P(hq), free_size);
CLEAR_PREV_ALLOCATED(NEXT_HEADER_P(hq));
list_insert(hq);
}
return PAYLOAD(hp);
}
// 将hp从对应的free list中移除
static void list_remove(void *hp) {
LIST_PREV(LIST_NEXT(hp)) = LIST_PREV(hp);
LIST_NEXT(LIST_PREV(hp)) = LIST_NEXT(hp);
}
// 将hp插入到对应的free list中
// FIFO policy 把新节点插入到链表尾部
static void list_insert(void *hp) {
void *root = ROOT(LOG2(BLOCK_SIZE(hp)));
void *prev = LIST_PREV(root);
LIST_PREV(root) = hp;
LIST_NEXT(prev) = hp;
LIST_PREV(hp) = prev;
LIST_NEXT(hp) = root;
}
//hp表示要分割的块的header pointer
//size表示要分割出来的块的大小
//higher表示是否使用高地址部分(低地址放小块,高地址放大块)
static void *split(void *hp, size_t size, int higher) {
size_t free_size = BLOCK_SIZE(hp) - size;
if (free_size >= MIN_SIZE) {
if (higher) {
PUT(hp, PACK(free_size, PREV_ALLOCATED(hp)));
PUT(FOOTER_P(hp), free_size);
list_insert(hp);
hp = (char *)hp + free_size;
DEREF(hp) = size | 1;
MARK_PREV_ALLOCATED(NEXT_HEADER_P(hp));
}
else {
PUT(hp, PACK(size, PREV_ALLOCATED(hp) | 1));
void *hq = (char *)hp + size;
PUT(hq, PACK(free_size, 2));
PUT(FOOTER_P(hq), free_size);
CLEAR_PREV_ALLOCATED(NEXT_HEADER_P(hq));
list_insert(hq);
}
}
return hp;
}
//合并相邻的空闲块,并将合并后的块插入到对应的free list中
//hp表示要合并的块的header pointer
static void *coalesce(void *hp) {
void *prev = PREV_HEADER_P(hp);
void *next = NEXT_HEADER_P(hp);
size_t size = BLOCK_SIZE(hp);
int prev_alloc = PREV_ALLOCATED(hp);
int next_alloc = ALLOCATED(next);
if(!prev_alloc) {// 之前的块是空闲块
size += BLOCK_SIZE(prev);
list_remove(prev);
hp = prev;
}
if(!next_alloc) {// 之后的块是空闲块
size += BLOCK_SIZE(next);
list_remove(next);
}
PUT(hp, PACK(size, PREV_ALLOCATED(hp)));
PUT(FOOTER_P(hp), size);
list_insert(hp);
return hp;
}
// 懒惰合并,之后free时会进行coalesce,插入到对应的free list中
// size会保证至少是MIN_EXPAND_SIZE
// 扩展堆空间大小,返回扩展后的块的指针
// 需要注意的是,扩展后的块在这里发生合并,但是并没有插入到对应的free list中
static void *extend(size_t size) {
size = MAX(size, MIN_EXPAND_SIZE);
size_t *hp = mem_sbrk(size);
if (hp == (void *)-1)
return NULL;
hp -= 1;
PUT(hp, PACK(size, PREV_ALLOCATED(hp)));
DEREF((char *)hp + size) = 1;
//coalesce without insert
void *prev = PREV_HEADER_P(hp);
void *next = NEXT_HEADER_P(hp);
int prev_alloc = PREV_ALLOCATED(hp);
int next_alloc = ALLOCATED(next);
if(!prev_alloc){
size += BLOCK_SIZE(prev);
list_remove(prev);
hp = prev;
}
if(!next_alloc){
size += BLOCK_SIZE(next);
list_remove(next);
}
PUT(hp, PACK(size, PREV_ALLOCATED(hp)));
PUT(FOOTER_P(hp), size);
return hp;
}