/
mm_old.c
394 lines (313 loc) · 8.99 KB
/
mm_old.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
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/*
* mm-naive.c - The fastest, least memory-efficient malloc package.
*
* In this naive approach, a block is allocated by simply incrementing
* the brk pointer. A block is pure payload. There are no headers or
* footers. Blocks are never coalesced or reused. Realloc is
* implemented directly using mm_malloc and mm_free.
*
* NOTE TO STUDENTS: Replace this header comment with your own header
* comment that gives a high level description of your solution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "mm.h"
#include "memlib.h"
/*********************************************************
* NOTE TO STUDENTS: Before you do anything else, please
* provide your team information in the following struct.
********************************************************/
team_t team = {
/* Team name */
"your_student_id",
/* First member's full name */
"your_name",
/* First member's email address */
"your_name@sjtu.edu.cn",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""
};
/* single word (4) or double word (8) alignment */
#define ALIGNMENT 8
/* rounds up to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
/* check the sign mark in a size_t value */
#define SIGN_CHECK(value) (((long) (value)) < 0)
/* change the sign mark in a size_t value */
#define SIGN_MARK(value) (~(value))
/* maximum value of size_t */
#define SIZE_T_MAX ((size_t) -1)
/* aligned size of size_t */
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
/* aligned size of blocks' header */
#define MM_HEADER_SIZE (ALIGN(sizeof(MMHeader)))
/* the least size of an useful block */
#define USEFUL_SIZE (MM_HEADER_SIZE + ALIGNMENT)
/*
* options of memory allocator
*/
/* if the block can fit */
/* best fit */
// #define MM_FIT(need, size) (0)
/* mixed fit */
// #define MM_FIT(need, size) (((size) << 1) < (need))
/* first fit */
#define MM_FIT(need, size) (1)
/* if searching is enabled (not only breaking) */
/* always */
// #define MM_SEARCH() (1)
/* cond 1 */
// #define MM_SEARCH() (total_alloc - total_free < (total_brk >> 1))
/* block first */
#define MM_SEARCH() (total_alloc > need_size)
/* if check param of functions */
// #define MM_CHECK
/* cast a void pointer to a header pointer */
#define MM(ptr) ((MMHeader *) (ptr))
/* header of a data block */
typedef struct {
/* size of the block, apply SIGN_MARK if the block is not used */
size_t size;
} MMHeader;
/* first free block */
void *first_free;
/* historical data */
size_t total_alloc = 0;
size_t total_free = 0;
size_t total_brk = 0;
/*
* mm_first_free - Get and also update first_free.
*/
inline void *mm_first_free(void)
{
void *now = first_free;
size_t now_size = 0;
// scan the block list
while ((now - 1) != mem_heap_hi()) {
now_size = MM(now)->size;
if (SIGN_CHECK(now_size)) {
break;
} else {
now += now_size;
}
}
// write back
first_free = now;
return now;
}
/*
* mm_get_first_free - Access first_free.
*/
inline void *mm_get_first_free(void)
{
return first_free;
}
/*
* mm_set_first_free - Change first_free.
*/
inline void mm_set_first_free(void *ptr)
{
first_free = ptr;
}
/*
* mm_put_header - Generate the header of a block and return the data section.
*/
inline void *mm_put_header(void *ptr, size_t size)
{
MM(ptr)->size = size;
return ptr + MM_HEADER_SIZE;
}
/*
* mm_restore_header - Get the header of a block from a data pointer.
*/
inline void *mm_restore_header(void *ptr)
{
return ptr - MM_HEADER_SIZE;
}
/*
* mm_print - Print block list for debug purpose.
*/
void mm_print(void)
{
void *now = mem_heap_lo();
size_t now_size = 0;
printf("\n");
// scan the block list
while ((now - 1) != mem_heap_hi()) {
now_size = MM(now)->size;
printf("pos: %x - head: %x\n", (unsigned) now, now_size);
// visit the next block
now += SIGN_CHECK(now_size) ? SIGN_MARK(now_size) : now_size;
}
}
/*
* mm_merge - Try to merge with next free block.
*/
inline int mm_merge(void *ptr, size_t *p_size)
{
void *next = ptr + *p_size;
size_t next_size = MM(next)->size;
// if the next block can be merged
if ((next - 1) != mem_heap_hi() && SIGN_CHECK(next_size)) {
*p_size += SIGN_MARK(next_size);
mm_put_header(ptr, SIGN_MARK(*p_size));
return -1;
} else {
return 0;
}
}
/*
* mm_split - Split from a block if it is possible, and use part of it.
*/
inline void *mm_split(void *ptr, size_t size, size_t need_size)
{
size_t more_size = size - need_size;
// if these is more space for another block
if (more_size >= USEFUL_SIZE) {
// create another block
mm_put_header(ptr + need_size, SIGN_MARK(more_size));
// generate the block
return mm_put_header(ptr, need_size);
} else {
// wasted size
total_alloc += more_size;
// generate the block
return mm_put_header(ptr, size);
}
}
/*
* mm_break - Extend the last block.
*/
inline void *mm_break(void *ptr, size_t size, size_t need_size)
{
size_t brk_size = need_size - size;
// historical data
total_brk += brk_size;
// extense the heap
mem_sbrk(brk_size);
// generate the block
return mm_put_header(ptr, need_size);
}
/*
* mm_init - Initialize the malloc package.
*/
int mm_init(void)
{
mm_set_first_free(mem_heap_lo());
// put a small block to hold some data
mem_sbrk(48);
mm_put_header(mem_heap_lo(), SIGN_MARK(48));
total_alloc = 0;
total_free = 0;
total_brk = 0;
return 0;
}
/*
* mm_malloc - Allocate a block.
* Always allocate a block whose size is a multiple of the alignment.
*/
void *mm_malloc(size_t size)
{
#ifdef MM_CHECK
if (!size) return;
#endif
void *now = mm_first_free();
void *best = NULL;
size_t now_size = 0;
size_t best_size = SIZE_T_MAX;
size_t need_size = MM_HEADER_SIZE + ALIGN(size);
// historical data
total_alloc += need_size;
if (MM_SEARCH()) {
// scan the block list
// if the best one is not found, keep best == NULL
// if the last one is used, let now_size == 0
while ((now - 1) != mem_heap_hi()) {
now_size = MM(now)->size;
if (SIGN_CHECK(now_size)) {
// current block is not used
now_size = SIGN_MARK(now_size);
// try to merge useable blocks
while (now_size < need_size && mm_merge(now, &now_size));
// check if this block is useable and useful
if (now_size >= need_size && now_size < best_size) {
best = now;
best_size = now_size;
if (MM_FIT(need_size, now_size)) break;
}
// visit the next block
now += now_size;
} else {
// current block is used
// visit the next block
now += now_size;
// reset now_size
now_size = 0;
}
}
if (best) {
// there is useable block and splitting is possible
return mm_split(best, best_size, need_size);
} else {
// there is no useable block and sbrk is needed
return mm_break(now - now_size, now_size, need_size);
}
} else {
// force sbrk
return mm_break(mem_heap_hi() + 1, 0, need_size);
}
}
/*
* mm_free - Free a block.
*/
void mm_free(void *ptr)
{
#ifdef MM_CHECK
if (!ptr) return;
#endif
void *now = mm_restore_header(ptr);
// historical data
total_free += MM(now)->size;
// change first_free
if (now < mm_get_first_free()) {
mm_set_first_free(now);
}
// mark it as an unused block
mm_put_header(now, SIGN_MARK(MM(now)->size));
}
/*
* mm_realloc - Change the size of a block.
*/
void *mm_realloc(void *ptr, size_t size)
{
#ifdef MM_CHECK
if (!ptr) return mm_malloc(size);
if (!size) return mm_free(ptr);
#endif
void *now = mm_restore_header(ptr);
void *dest;
size_t now_size = MM(now)->size;
size_t need_size = MM_HEADER_SIZE + ALIGN(size);
// try to merge useable blocks
while (now_size < need_size && mm_merge(now, &now_size));
if (now_size >= need_size) {
// the block can be locally extensed and splitting is possible
return mm_split(now, now_size, need_size);
} else {
if ((now + now_size - 1) == mem_heap_hi()) {
// the block is the last block and it can be extensed
return mm_break(now, now_size, need_size);
} else {
// need to allocate a new block and copy data to it
dest = mm_malloc(size);
memcpy(dest, ptr, MM(now)->size - MM_HEADER_SIZE);
mm_free(ptr);
return dest;
}
}
}