隐式空闲链表
我是过了书本上的代码实现。writeup是英文版的,很多人可能不会注意到实验需要的trace文件是需要自己配置的。trace文件在这里。另外记得配置config.h文件。
config.h
#define TRACEDIR "./traces/" <----------- 看这里
/*
* This is the list of default tracefiles in TRACEDIR that the driver
* will use for testing. Modify this if you want to add or delete
* traces from the driver's test suite. For example, if you don't want
* your students to implement realloc, you can delete the last two
* traces.
*/
#define DEFAULT_TRACEFILES \
"amptjp-bal.rep",\
"cccp-bal.rep",\
"cp-decl-bal.rep",\
"expr-bal.rep",\
"coalescing-bal.rep",\
"random-bal.rep",\
"random2-bal.rep",\
"binary-bal.rep",\
"binary2-bal.rep",\
"realloc-bal.rep",\
"realloc2-bal.rep"
mm.c
#define WSIZE 4 //单字
#define DSIZE 8 //双字
#define CHUNKSIZE (1<<12) //当内存不够时,向内核申请的堆空间
#define GET(p) (*(unsigned int*)(p))
#define PUT(p, val) (*(unsigned int*)(p) = (val)) //将val放入p开始的4字节中
#define PACK(size, alloc) ((size) | (alloc)) //将块大小和分配为拼凑成字,可作为块的头部或脚部
#define GET_SIZE(p) (GET(p) & ~0x7) //从头部或脚部获取块的大小
#define GET_ALLOC(p) (GET(p) & 0x1) //从头部或脚部获取块的分配信息
#define HDRP(bp) ((char*)(bp) - WSIZE) //获得块的头部指针
#define FTRP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) //获得块的尾部指针
#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp))) //获得下一个块的指针
#define PREV_BLKP(bp) ((char*)(bp) - GET_SIZE((char*)(bp) - DSIZE)) //获得上一个块的指针
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/* 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)
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
static char *heap_listp = 0; //指向第一个块的指针
#ifdef NEXT_FIT
static char *rover;
#endif
static void *extend_heap(size_t words);
static void place(void *bp, size_t asize);
static void *find_fit(size_t asize);
static void *coalesce(void *bp);
/*
* mm_init - initialize the malloc package.
*/
int mm_init(void) {
if ((heap_listp = mem_sbrk(4 * WSIZE)) == (void *) -1)
return -1;
PUT(heap_listp, 0); //未使用的堆的起始位置
PUT(heap_listp + WSIZE, PACK(DSIZE, 1)); //序言块头部
PUT(heap_listp + DSIZE, PACK(DSIZE, 1)); //序言块脚部
PUT(heap_listp + 3 * WSIZE, PACK(0, 1)); //结尾块头部 结尾块只有头部
heap_listp += (2 * WSIZE); //heap_listp指向第一个块的有效载荷的开始处
#ifdef NEXT_FIT
rover = heap_listp;
#endif
if (extend_heap(CHUNKSIZE / WSIZE) == NULL)
return -1;
return 0;
}
/*
* mm_malloc - Allocate a block by incrementing the brk pointer.
* Always allocate a block whose size is a multiple of the alignment.
*/
void *mm_malloc(size_t size) {
size_t asize;
size_t extendsize;
char *bp;
if (heap_listp == 0) {
mm_init();
}
if (size == 0) return NULL;
//块的大小要加上头部、脚部和对其块
if (size <= DSIZE)
asize = 2 * DSIZE;
else
asize = DSIZE * ((size + (DSIZE) + (DSIZE - 1)) / DSIZE);
if ((bp = find_fit(asize)) != NULL) {
place(bp, asize);
return bp;
}
extendsize = MAX(asize, CHUNKSIZE);
if ((bp = extend_heap(extendsize / WSIZE)) == NULL)
return NULL;
place(bp, asize);
return bp;
}
/*
* mm_free - Freeing a block does nothing.
*/
void mm_free(void *bp) {
if (bp == 0)
return;
size_t size = GET_SIZE(HDRP(bp));
if (heap_listp == 0) {
mm_init();
}
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
coalesce(bp);
}
/*
* mm_realloc - Implemented simply in terms of mm_malloc and mm_free
*/
void *mm_realloc(void *bp, size_t size) {
size_t oldsize;
void *newbp;
if (size == 0) {
mm_free(bp);
return 0;
}
if (bp == NULL) return mm_malloc(size);
newbp = mm_malloc(size);
if (!newbp) return 0;
oldsize = GET_SIZE(HDRP(bp));
if (size < oldsize) oldsize = size;
memcpy(newbp, bp, oldsize);
mm_free(bp);
return newbp;
}
static void *extend_heap(size_t words) {
char *bp;
size_t size;
size = (words % 2) ? (words + 1) * WSIZE : words * WSIZE;
if ((long) (bp = mem_sbrk(size)) == -1)
return NULL;
PUT(HDRP(bp), PACK(size, 0)); // 释放块的头部
PUT(FTRP(bp), PACK(size, 0)); // 释放块的脚部
PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); // 设置新的结尾块头部
return coalesce(bp); //执行合并函数
}
static void *coalesce(void *bp) {
size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));
if (prev_alloc && next_alloc) //不需要合并
return bp;
else if (prev_alloc && !next_alloc) { //合并下一个块
size += GET_SIZE(HDRP(NEXT_BLKP(bp)));
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
} else if (!prev_alloc && next_alloc) { //合并上一个块
size += GET_SIZE(HDRP(PREV_BLKP(bp)));
PUT(FTRP(bp), PACK(size, 0));
PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));
bp = PREV_BLKP(bp);
} else { //上下两个块都可以合并
size += GET_SIZE(HDRP(PREV_BLKP(bp))) +
GET_SIZE(FTRP(NEXT_BLKP(bp)));
PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));
PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0));
bp = PREV_BLKP(bp);
}
#ifdef NEXT_FIT
if((rover > (char*)bp) && (rover < NEXT_BLKP(bp)))
rover = bp;
#endif
return bp;
}
//支持首次适配和下一个适配
static void *find_fit(size_t asize) {
#ifdef NEXT_FIT
char *oldrover = rover;
//从rover向后找
for(; GET_SIZE(HDRP(rover)) > 0; rover = NEXT_BLKP(rover))
if(!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover))))
return rover;
//从heap_listp(第一个块的位置)到rover之间找
for(rover = heap_listp; rover < oldrover; rover = NEXT_BLKP(rover))
if(!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover))))
return rover;
return NULL;
#else
void *bp;
for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) {
if (!GET_ALLOC(HDRP(bp)) && (asize <= GET_SIZE(HDRP(bp))))
return bp;
}
return NULL;
#endif
}
//放置新块 如果新块足够大,则将新块分割成两块
static void place(void *bp, size_t asize) {
size_t csize = GET_SIZE(HDRP(bp));
if ((csize - asize) >= (2 * DSIZE)) {
PUT(HDRP(bp), PACK(asize, 1));
PUT(FTRP(bp), PACK(asize, 1));
bp = NEXT_BLKP(bp);
PUT(HDRP(bp), PACK(csize - asize, 0));
PUT(FTRP(bp), PACK(csize - asize, 0));
} else {
PUT(HDRP(bp), PACK(csize, 1));
PUT(FTRP(bp), PACK(csize, 1));
}
}
首次适配和下一次适配的实验差异
首次适配
Results for mm malloc:
trace valid util ops secs Kops
0 yes 99% 5694 0.009491 600
1 yes 99% 5848 0.008619 679
2 yes 99% 6648 0.013775 483
3 yes 100% 5380 0.009965 540
4 yes 66% 14400 0.000297 48518
5 yes 92% 4800 0.009877 486
6 yes 92% 4800 0.008335 576
7 yes 55% 12000 0.182477 66
8 yes 51% 24000 0.338548 71
9 yes 27% 14401 0.101787 141
10 yes 34% 14401 0.003621 3977
Total 74% 112372 0.686791 164
Perf index = 44 (util) + 11 (thru) = 55/100
下一次适配
Results for mm malloc:
trace valid util ops secs Kops
0 yes 91% 5694 0.002184 2607
1 yes 92% 5848 0.002154 2714
2 yes 95% 6648 0.005886 1129
3 yes 97% 5380 0.004869 1105
4 yes 66% 14400 0.000202 71181
5 yes 91% 4800 0.006786 707
6 yes 89% 4800 0.005889 815
7 yes 55% 12000 0.018857 636
8 yes 51% 24000 0.011408 2104
9 yes 27% 14401 0.108006 133
10 yes 45% 14401 0.003796 3794
Total 73% 112372 0.170037 661
Perf index = 44 (util) + 40 (thru) = 84/100