【深入理解计算机系统csapp lab】malloc lab

做malloclab首先要熟悉课本9.9的内容,尤其是9.9.12,如果不知道从哪里入手,可以和我一样,从实现课本介绍的简单分配器开始,然后在这个基础上改编。
试验后最终采取的是隐式空闲链表+分离的显式空闲链表,分离存储的块大小为{16-32},{33-64},{65-128}···,空闲块在链表中按从小到大排列,这样首次匹配的结果接近最佳匹配。

mm.h

#include 

extern int mm_init (void);
extern void *mm_malloc (size_t size);
extern void mm_free (void *ptr);
extern void *mm_realloc(void *ptr, size_t size);


/* 
 * Students work in teams of one or two.  Teams enter their team name, 
 * personal names and login IDs in a struct of this
 * type in their bits.c file.
 */
typedef struct {
    char *teamname; /* ID1+ID2 or ID1 */
    char *name1;    /* full name of first member */
    char *id1;      /* login ID of first member */
    char *name2;    /* full name of second member (if any) */
    char *id2;      /* login ID of second member */
} team_t;

extern team_t team;

#define WSIZE 4 
#define DSIZE 8

#define MAX(x,y) ((x)>(y)?(x):(y))

#define PACK(size,alloc) ((size)|(alloc))

#define GET(p) (*(unsigned int*) (p))
#define PUT(p,val) (*(unsigned int *)(p)=(unsigned int)(val))

#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 NEXT_PTR(bp) ((char*)(bp))//空闲链表下一个地址的地址
#define PREV_PTR(bp) ((char*)(bp)+WSIZE)//空闲链表上一个地址的地址

#define NEXT(bp) (*(char**)(NEXT_PTR(bp)))//空闲链表下一个块地址
#define PREV(bp) (*(char**)(PREV_PTR(bp)))//空闲链表上一个块地址

mm.c

/*
 * 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 
#include 
#include 
#include 
#include 

#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 */
    "ateam",
    /* First member's full name */
    "Shuyu",
    /* First member's email address */
    "[email protected]",
    /* 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

#define CHUNKSIZE 1<<12 //CHUNKSIZE一定要>=2*DSIZE

/* rounds up to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)


#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
#define LISTLEN 20 //分离的空闲链表个数

static void* heap_listp; 
static void* segregated_header[LISTLEN]; //分离空闲链表


static void* extend_heap(size_t words); //拓展堆words个字
static void* coalesce(void* bp); //如果bp前后相邻空闲块,合并之
static void* find_fit(size_t asize); //寻找能够容纳asize字节的空闲块(初次匹配)
static void place(void* bp,size_t asize); //在bp指向的空闲块中分配asize空间,如果空闲块剩余空间>=2*DSIZE,将其再插入合适的空闲链表中
static int list_index(size_t asize); //返回asize大小的空闲块所在空闲链表的索引
static void insert_free(void* bp,size_t asize);  //插入bp指向的asize大小的空闲块到空闲链表中
static void delete_free(void* bp); //在空闲链表中删除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+(1*WSIZE),PACK(DSIZE,1));//序言块
	PUT(heap_listp+(2*WSIZE),PACK(DSIZE,1));//序言块
	PUT(heap_listp+(3*WSIZE),PACK(0,1));//结尾块

	heap_listp+=2*WSIZE;

	//初始化分离链表
	for(int i=0;i<LISTLEN;i++)
		segregated_header[i]=NULL;

	//扩展堆
	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;
    
	//计算分配空间的实际大小asize,不小于2*DSIZE,要对齐  
	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 *ptr)
{
	//置为空闲块
	PUT(HDRP(ptr),PACK(GET_SIZE(HDRP(ptr)),0));
	PUT(FTRP(ptr),PACK(GET_SIZE(HDRP(ptr)),0));
	//如果bp前后相邻空闲块,合并之
	ptr=coalesce(ptr);
	//插入到空闲链表
	insert_free(ptr,GET_SIZE(HDRP(ptr)));
}

/*
 * mm_realloc - Implemented simply in terms of mm_malloc and mm_free
 */
void *mm_realloc(void *ptr, size_t size)
{
	void *oldptr = ptr;
        void *newptr;
	size_t asize;
	
	//处理ptr==NULL和size==0的情况
	if(ptr==NULL)
		return mm_malloc(size);     	
	if(size==0){
		insert_free(ptr,GET_SIZE(HDRP(ptr)));
		return NULL;
	}

	
	//计算分配空间的实际大小asize,不小于2*DSIZE,要对齐  
	if(size<=DSIZE)
		asize=2*DSIZE;
	else
		asize=DSIZE*((size+(DSIZE)+(DSIZE-1))/DSIZE);


	size_t copySize,oldsize;

	//空间的原大小oldsize
	oldsize=GET_SIZE(HDRP(ptr));
    
	//如果原空间足够大,仍然在原空间分配
	if(oldsize>=asize){        	
		place(ptr,asize);
		newptr=ptr;
	}
	//如果原空间不够大
    	else{
		//试合并前后块
		ptr=coalesce(ptr);
		//如果合并后能够容纳asize,则在合并后的空间中分配
        	if(GET_SIZE(HDRP(ptr))>=asize){
	    		newptr=ptr;
			if(newptr!=oldptr){//如果向前合并了,需要拷贝数据
	    			copySize=oldsize-DSIZE;
	   			if (size < copySize)
	        			copySize = size;
	    			memmove(newptr, oldptr, copySize);//memcpy无法处理重叠情况,所以用memmove
			}
	    	place(newptr,asize);
		}
		//如果合并后仍然不够容纳asize,则malloc新空间,拷贝数据,释放原空间
		else{
	    		newptr = mm_malloc(size);
	    		if (newptr == NULL)
	        		return NULL;
	    		copySize = oldsize-DSIZE;
	    		if (size < copySize)
	        		copySize = size;
	    		memcpy(newptr, oldptr, copySize);
	   		insert_free(ptr,GET_SIZE(HDRP(ptr)));
		}
    	}
    return newptr;
}


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));//结尾块
	bp=coalesce(bp);//合并空闲块
	insert_free(bp,GET_SIZE(HDRP(bp)));//插入空闲链表
	return 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));

	//根据前后块分配情况分四种情况设置头、尾,但不把新块插入空闲队列(因为realloc用到此函数,插入空闲队列的操作会破坏原数据)
	if(prev_alloc && next_alloc){
		PUT(HDRP(bp),PACK(size,0));
		PUT(FTRP(bp),PACK(size,0));
	}
	else if(prev_alloc&&!next_alloc){
		delete_free(NEXT_BLKP(bp));
		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){
		delete_free(PREV_BLKP(bp));
		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{
		delete_free(PREV_BLKP(bp));
		delete_free(NEXT_BLKP(bp));
		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);
	}
	return bp;
}



static void* find_fit(size_t asize){
	void* bp;

	for(int i=list_index(asize);i<LISTLEN;i++){//从asize对应的空闲链表开始向后查找
		if(segregated_header[i]){
			for(bp=segregated_header[i];bp;bp=NEXT(bp))
				if(asize<=GET_SIZE(HDRP(bp)))
					return bp;//首次匹配		
		}
	}

	return NULL;
}

static void place(void* bp,size_t asize){
	if(!GET_ALLOC(FTRP(bp)))
		delete_free(bp);
	size_t csize=GET_SIZE(HDRP(bp));

	//剩余空间如果大于等于最小块(2*DSIZE),则将剩余空间置空闲块
	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));
		insert_free(bp,csize-asize);
	}
	else{
		PUT(HDRP(bp),PACK(csize,1));
		PUT(FTRP(bp),PACK(csize,1));
	}

}

static int list_index(size_t asize){
	int size=16;//分离链表:[8~16][17~32][33~64]...
	for(int i=0;i<LISTLEN;i++){
		if(size>=asize) return i;
		size=size<<1;		
	}
	return LISTLEN-1;
}

static void insert_free(void* bp,size_t asize){//将asize的空闲块放入相应的空闲链表中,按从小到大的顺序存放
	PUT(HDRP(bp),PACK(asize,0));
	PUT(FTRP(bp),PACK(asize,0));//设置头尾
	int listi=list_index(asize);
	void* p=segregated_header[listi];//listi:对应链表头结点
	void* pre=NULL;//查找中的前驱结点指针
	if(segregated_header[listi]==NULL){//如果对应链表为空,那么直接插入bp为头结点
		PUT(NEXT_PTR(bp),NULL);
		PUT(PREV_PTR(bp),0);
		segregated_header[listi]=bp;
	}
	else{//如果链表不为空
		while(p&&GET_SIZE(HDRP(p))<asize){
			pre=p;	
			p=NEXT(p);
		}//遍历链表直到结尾或找到大于等于asize的结点p
		if(pre==NULL)
			segregated_header[listi]=bp;//如果pre==NULL,说明头结点就大于等于asize,那么bp应该是新的头结点 
		else	
			PUT(NEXT_PTR(pre),bp);//否则如果pre!=NULL,那么bp是pre的后继
		PUT(NEXT_PTR(bp),p);//p是bp的后继
		PUT(PREV_PTR(bp),pre);//pre是bp的前驱
		if(p) PUT(PREV_PTR(p),bp);//bp是p的前驱

	}

}

static void delete_free(void* bp){
	int listi=list_index(GET_SIZE(HDRP(bp)));//listi:对应链表头结点
	if(NEXT(bp)==NULL&&PREV(bp)==NULL){//如果bp是链表上的唯一结点,删除该结点,置对应链表为空
		segregated_header[listi]=NULL;
	}
	else if(PREV(bp)==NULL){//如果bp是头结点,置头结点为bp的后继结点
		segregated_header[listi]=NEXT(bp);
		PUT(PREV_PTR(NEXT(bp)),0);
	}
	else if(NEXT(bp)==NULL){//如果bp是末尾结点,置前驱结点为末尾结点
		PUT(NEXT_PTR(PREV(bp)),0);
	}
	else{//如果bp是中间结点,连接它的前驱和后继结点
		PUT(PREV_PTR(NEXT(bp)),PREV(bp));
		PUT(NEXT_PTR(PREV(bp)),NEXT(bp));
	}

}

最后测试的成绩是88分

Team Name:ateam
Member 1 :Shuyu:[email protected]
Using default tracefiles in /home/hazel/malloclab-handout/traces/
Measuring performance with gettimeofday().

Results for mm malloc:
trace  valid  util     ops      secs  Kops
 0       yes   99%    5694  0.000386 14740
 1       yes   99%    5848  0.000291 20110
 2       yes   99%    6648  0.000338 19657
 3       yes  100%    5380  0.000281 19119
 4       yes   99%   14400  0.000321 44916
 5       yes   96%    4800  0.000760  6317
 6       yes   96%    4800  0.000717  6695
 7       yes   55%    6000  0.000220 27236
 8       yes   51%    7200  0.000246 29304
 9       yes   40%   14401  0.000866 16622
10       yes   46%   14401  0.000493 29217
Total          80%   89572  0.004919 18208

Perf index = 48 (util) + 40 (thru) = 88/100

你可能感兴趣的:(csapp)