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

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

mm.h

#include <stdio.h>

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 <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 */
    "ateam",
    /* First member's full name */
    "Shuyu",
    /* First member's email address */
    "liushuyuwww@163.com",
    /* 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:liushuyuwww@163.com
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

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 深入理解计算机系统(CSAPP)是由Randal E. Bryant和David R. O'Hallaron编写的经典计算机科学教材。该教材通过涵盖计算机体系结构、机器级别表示和程序执行的概念,帮助学生深入理解计算机系统的底层工作原理和运行机制。 深入理解计算机系统的练习题对于学生巩固并应用所学知识非常有帮助。这些练习题涵盖了计算机硬件、操作系统和编译器等多个领域,旨在培养学生解决实际问题和设计高性能软件的能力。 对于深入理解计算机系统的练习题,关键是通过实践进行学习。在解答练习题时,应根据课本提供的相关知识和工具,仔细阅读问题描述,并根据实际需求设计相应的解决方案。 在解答练习题时,需要多角度思考问题。首先,应准确理解题目要求,并设计合适的算法或代码来解决问题。其次,应考虑代码的正确性和效率,以及对系统性能的影响。此外,还要注意处理一些特殊情况和异常情况,避免出现潜在的错误或安全漏洞。 解答练习题的过程中,应注重查阅相关资料和参考优秀的解答。这可以帮助我们扩展对问题的理解,并学习他人的思路和解决方法。同时,还可以通过与同学和老师的讨论,共同探讨问题和学习经验。 总之,通过解答深入理解计算机系统的练习题,可以帮助学生巩固所学知识,同时培养解决实际问题和设计高性能软件的能力。这是一个学以致用的过程,可以加深对计算机系统运行机制和底层工作原理的理解。 ### 回答2: 理解计算机系统(CSAPP)是一本经典的计算机科学教材,通过深入研究计算机系统的各个方面,包括硬件、操作系统和编程环境,对于提高计算机科学专业知识与能力具有很大帮助。 练习题是CSAPP中的重要部分,通过练习题的完成,可以加深对计算机系统的理解,并将理论知识转化为实践能力。练习题的数量、难度逐渐递增,从简单的概念与基础问题到复杂的系统设计与实现。 在解答练习题时,首先需要对题目进行仔细阅读和理解,明确题目的要求和限制条件。然后,可以利用课堂讲解、教材内容、网络资源等进行查阅和学习相应的知识。同时,还可以参考课后习题解答等资料,了解一些常见的解题方法和思路。 在解答练习题时,可以利用计算机系统的工具和环境进行实际测试和验证。例如,可以使用调试器、编译器和模拟器等工具对程序或系统进行分析和测试。这样可以更加深入地理解问题的本质,并找到恰当的解决方法。 另外,解答练习题时还可以与同学、教师和网上社区进行交流和讨论。这样可以互相学习和交流解题思路,共同解决问题。还可以了解不同的解题方法和技巧,提高解题效率和质量。 练习题的解答过程可能会遇到一些困难和挑战,例如理论知识的不足、复杂问题的分析与解决。但是通过不断地思考和实践,相信可以逐渐提高解题能力,更好地理解计算机系统。 总之,深入理解计算机系统(CSAPP)练习题是提高计算机科学专业知识和能力的重要途径。通过仔细阅读和理解题目,查阅相关知识,利用计算机系统工具和环境进行实践,与他人进行交流和讨论,相信可以更好地理解计算机系统的各个方面,并将知识转化为实际能力。 ### 回答3: 《深入理解计算机系统(CSAPP)》是计算机科学领域的经典教材之一,对于深入理解计算机系统的原理、设计和实现起到了极大的帮助。在阅读这本书的过程中,书中的习题也是非常重要的一部分,通过做习题,我们可以更好地理解书中所讲的概念和思想。 CSAPP的习题涵盖了课本中各个章节的内容,从基础的数据表示和处理、程序的机器级表示、优化技术、程序的并发与并行等方面进行了深入探讨。通过解答习题,我们可以对这些知识进行实践应用,巩固自己的理解,并培养自己的解决问题的思维方式。 在解答习题时,我们需要充分理解题目要求和条件,并从知识的角度进行分析。有些习题可能需要进行一些编程实践,我们可以通过编程实现来验证和测试我们的思路和解决方案。在解答问题时,我们还可以查阅一些参考资料和网上资源,充分利用互联网的学习资源。 在解答习题时,我们需要保持积极的思维和态度。可能会遇到一些困难和挑战,但是通过坚持和努力,我们可以克服这些困难,提高我们的解决问题的能力。同时,我们还可以通过与同学或者其他人进行讨论,相互分享解题经验和思路,从而更好地理解问题。 综上所述,通过深入理解计算机系统(CSAPP)的习题,我们可以进一步巩固和深化对计算机系统的理解。掌握这些知识,不仅可以提高我们在计算机领域的能力,还可以为我们未来的学习和职业发展奠定重要的基础。因此,认真对待CSAPP的习题,是我们在学习计算机系统知识中不可或缺的一部分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值