CSAPP:MallocLab
Malloc Lab
做什么?
实现一个内存分配器
怎么做?
非常建议看完书后,自己写一遍,进步非常大,可以检测出你哪块理解不够深刻,可以将这块知识点吃的很透彻。在遇到瓶颈的时候看看人家怎么写的,不然写出的代码有局限性,结果都不太好。比如说我的方案只按照书上的提示走,没有考虑各种方法相结合所以具有局限性,博客可以看https://zhuanlan.zhihu.com/p/126341872 这位大佬的
隐式链表实现(按照9.9.12思路编写)
/** 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 */"Harry Bovik",/* First member's email address */"bovik@cs.cmu.edu",/* 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)
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
/* */
#define WSIZE 4 /* Word and header/footer size (bytes) */ //line:vm:mm:beginconst
#define DSIZE 8 /* Doubleword size (bytes) */
#define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */ //line:vm:mm:endconst
#define MAX(x, y) ((x) > (y)? (x) : (y))
/* Pack a size and allocated bit into a word */
#define PACK(size, alloc) ((size) | (alloc)) //line:vm:mm:pack
/* Read and write a word at address p */
#define GET(p) (*(unsigned int *)(p)) //line:vm:mm:get
#define PUT(p, val) (*(unsigned int *)(p) = (val)) //line:vm:mm:put
/* Read the size and allocated fields from address p */
#define GET_SIZE(p) (GET(p) & ~0x7) //line:vm:mm:getsize
#define GET_ALLOC(p) (GET(p) & 0x1) //line:vm:mm:getalloc
/* Given block ptr bp, compute address of its header and footer */
#define HDRP(bp) ((char *)(bp) - WSIZE) //line:vm:mm:hdrp
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) //line:vm:mm:ftrp
/* Given block ptr bp, compute address of next and previous blocks */
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) //line:vm:mm:nextblkp
#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) //line:vm:mm:prevblkp
static char *heap_listp;
static void *extend_heap(size_t words);
static void *coalesce(void *bp);
static void place(void *bp, size_t asize);
static void *find_fit(size_t asize);
static void *best_fit(size_t asize);
/* */
/* * mm_init - initialize the malloc package.*/
int mm_init(void)
{//四个W的空间,1个W是头,2个W的序言块,1个W的结尾块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);
if(extend_heap(CHUNKSIZE/WSIZE) == NULL)return -1;return 0;
}
static void *extend_heap(size_t words){//新申请的空间,中的head会覆盖原有空间的结尾块,并自己申请一个新块char *bp;size_t size;
size = (words % 2)? (words + 1) * WSIZE : words * WSIZE;if((long)(bp = mem_sbrk(size)) == (void *)-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);
}
/* * 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(size == 0){return NULL;}if(size <= DSIZE){asize = 2*DSIZE;//8字节满足对齐要求,8字节满足head和foot空间}else{asize = DSIZE * ((size + DSIZE + (DSIZE - 1)) / DSIZE);}/*if((bp = find_fit(asize))!=NULL){place(bp, asize);return bp;}*/if((bp = best_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)
{size_t size = GET_SIZE(HDRP(bp));
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 *ptr, size_t size){void *newptr;size_t oldsize = GET_SIZE(HDRP(ptr));if(ptr==NULL)return mm_malloc(size);if(oldsize == size)return ptr;if(size == 0){mm_free(ptr);return NULL;}if(!(newptr = mm_malloc(size))){return NULL;}if(size < oldsize)oldsize = size;memcpy(newptr, ptr, oldsize);mm_free(ptr);return newptr;}
static void *coalesce(void *bp){size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp)));size_t next_alloc = GET_ALLOC(FTRP(NEXT_BLKP(bp)));size_t size = GET_SIZE(FTRP(bp));
if(prev_alloc && next_alloc){//case 1:两边都在用return bp;}else if(prev_alloc && !next_alloc){//case 2:下面空闲块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){//case 3:上面空闲块size += (GET_SIZE(HDRP(PREV_BLKP(bp))));PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));PUT(FTRP(bp), PACK(size, 0));bp = PREV_BLKP(bp);}else {//case 4:两边都空闲块size += (GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(HDRP(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 place(void *bp, size_t asize){size_t size = GET_SIZE(HDRP(bp));if((size - asize) >= 2*DSIZE){//剩下的空间足以构成一个最小块了。PUT(HDRP(bp), PACK(asize, 1));PUT(FTRP(bp), PACK(asize, 1));bp = NEXT_BLKP(bp);//便于操作PUT(HDRP(bp), PACK(size - asize, 0));PUT(FTRP(bp), PACK(size - asize, 0));}else{//化为内部碎片PUT(HDRP(bp), PACK(size, 1));PUT(FTRP(bp), PACK(size, 1));}
}
static void *find_fit(size_t asize){//首次适配void *bp;for(bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)){if((!GET_ALLOC(HDRP(bp))) && (GET_SIZE(HDRP(bp)) >= asize)){return bp;}}return NULL;
}
static void *best_fit(size_t asize){void *bp;size_t min_size, size;void *best_bp = NULL;int flag = 1;for(bp = heap_listp; (size = GET_SIZE(HDRP(bp))) > 0; bp = NEXT_BLKP(bp)){if((!GET_ALLOC(HDRP(bp))) && (size >= asize)){if(flag == 1){min_size = size;best_bp = bp;flag = 0;continue;}if(size < min_size){min_size = size;best_bp = bp;}}}return best_bp;
}
重要函数、变量以及注意点和思路:
static char *heap_listp
: 一个标记变量相当于第0个块的指向有效载荷的指针,其中第0个块并不会被分配。static void *extend_heap(size_t words)
从堆栈中申请新的空间,本质上是将mem_brk指针后移。申请之后执行立即合并,查看新申请的空间在物理的前后是否存在可合并的额外空闲块。static void *coalesce(void *bp)
根据书中的图9-40
来分别合并空闲块。static void place(void *bp, size_t asize)
分割空闲块,其中(size - asize) >= 2*DSIZE
为什么是2个DSIZE
因为对于这个分割器最小块的大小为2*DSIZE
字节,从哪里可以看出来呢?在mm_malloc
的size <= DSIZE
和其下一行可以看出,在书中也说明了这一点。static void *find_fit(size_t asize)
首次匹配,逻辑简单,好实现。static void *best_fit(size_t asize)
最佳匹配,在首次匹配的基础上记录最优指针和大小。static char *mem_start_brk; /* points to first byte of heap */
heap中的起始指针。static char *mem_brk; /* points to last byte of heap */
该指针指向heap已经分配出去的空间中的最后一个字节后面的那个字节static char *mem_max_addr; /* largest legal heap address */
允许可以申请的空间的最大地址。该值固定,其大小在config.h
中定义
注意点:
有了书中代码的提示其实并没有什么注意点,但是在写第二种方法时,发现还是了解的不够细致,比如
在该模型下使用mm_malloc到底在底层就申请这么多空间吗?在哪里额外多申请了一个DSIZE来放foot和head。
还有在
extend_heap
时,他还会新创立一个结尾块,那之前申请的结尾块会不会影响模型呢?答:新创立的空间的head会覆盖掉之前的结尾块,所以不用担心模型中会出现多个结尾块的问题。
显式空闲链表实现(书中9.9.13思路即显式链表+最佳匹配+LIFO)
/** 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.*/
//显式空闲链表+LIFO,序言块部分是16字节,4W,前驱后继都指向对应快的bp,这个方案只靠pred个succ指针来跳转方向
#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 */"Harry Bovik",/* First member's email address */"bovik@cs.cmu.edu",/* 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)
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
/* */
#define WSIZE 4 /* Word and header/footer size (bytes) */ //line:vm:mm:beginconst
#define DSIZE 8 /* Doubleword size (bytes) */
#define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */ //line:vm:mm:endconst
#define MAX(x, y) ((x) > (y)? (x) : (y))
/* Pack a size and allocated bit into a word */
#define PACK(size, alloc) ((size) | (alloc)) //line:vm:mm:pack
/* Read and write a word at address p */
#define GET(p) (*(unsigned int *)(p)) //line:vm:mm:get
#define PUT(p, val) (*(unsigned int *)(p) = (val)) //line:vm:mm:put
/* Read the size and allocated fields from address p */
#define GET_SIZE(p) (GET(p) & ~0x7) //line:vm:mm:getsize
#define GET_ALLOC(p) (GET(p) & 0x1) //line:vm:mm:getalloc
/* Given block ptr bp, compute address of its header and footer */
#define HDRP(bp) ((char *)(bp) - WSIZE) //line:vm:mm:hdrp
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) //line:vm:mm:ftrp
/* Given block ptr bp, compute address of next and previous blocks */
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) //line:vm:mm:nextblkp
#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) //line:vm:mm:prevblkp
#define SUCC_INDEX(bp) ((char *)(bp) + WSIZE)
#define PRED_INDEX(bp) ((char *)(bp))
static char *heap_listp;
static void *extend_heap(size_t words);
static void *coalesce(void *bp);
static void place(void *bp, size_t asize);
static void *find_fit(size_t asize);
static void *best_fit(size_t asize);
static void* addlist(void *bp);//将合并的链表新增到头
/* */
/* * mm_init - initialize the malloc package.*/
int mm_init(void)
{//printf("进入mm_init\n");//6个W的空间,1个W是头,4个W的序言块,1个W的结尾块if((heap_listp = mem_sbrk(6*WSIZE)) == (void *)-1){//printf("退出mm_init_1\n");return -1;}PUT(heap_listp, 0);PUT(heap_listp + (1*WSIZE), PACK(2*DSIZE, 1));//序言块头PUT(heap_listp + (2*WSIZE), NULL);PUT(heap_listp + (3*WSIZE), NULL);PUT(heap_listp + (4*WSIZE), PACK(2*DSIZE, 1));//序言块尾PUT(heap_listp + (5*WSIZE), PACK(0, 1));//结尾块-1w
heap_listp += (2*WSIZE);//相当于第一个块的bp
if(extend_heap(CHUNKSIZE/WSIZE) == NULL){//printf("退出mm_init_2\n");return -1;}//printf("退出mm_init_3\n");return 0;
}
static void *extend_heap(size_t words){char *bp;size_t size;//printf("进入extend_heap\n");size = (words % 2)? (words + 1) * WSIZE : words * WSIZE;if(size < 2*DSIZE)size = 2*DSIZE;//显式空闲链表最小空间为4Wif((long)(bp = mem_sbrk(size)) == (void *)-1){//printf("退出extend_heap_1\n");return NULL;}PUT(HDRP(bp), PACK(size, 0));PUT(FTRP(bp), PACK(size, 0));
PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1));//printf("退出extend_heap_2\n");return coalesce(bp);
}
/* * 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;//printf("进入mm_malloc\n");if(size == 0){//printf("退出mm_malloc\n");return NULL;}if(size < DSIZE){asize = 2*DSIZE;//8字节满足对齐要求,8字节满足head和foot空间}else{asize = DSIZE * ((size + DSIZE + (DSIZE - 1)) / DSIZE);//在这里多申请一个DISZE来存放foot和head}//printf("想找size:%d\n",asize);/*if((bp = find_fit(asize))!=NULL){//printf("退出mm_malloc_1\n");place(bp, asize);return bp;}*/if((bp = best_fit(asize))!=NULL){place(bp, asize);//printf("退出mm_malloc_1\n");return bp;}extendsize = MAX(asize, CHUNKSIZE);if((bp = extend_heap(extendsize/WSIZE)) == NULL){//printf("退出mm_malloc_2\n");return NULL;}place(bp, asize);//printf("退出mm_malloc_3\n");return bp;
}
/** mm_free - Freeing a block does nothing.*/
void mm_free(void *bp)
{//printf("进入mm_free\n");size_t size = GET_SIZE(HDRP(bp));PUT(HDRP(bp), PACK(size, 0));PUT(FTRP(bp), PACK(size, 0));
//LIFO
//PUT(SUCC_INDEX(bp), GET(SUCC_INDEX(heap_listp)));//本节点的后继为原heap_listp的后继//PUT(PRED_INDEX(GET(SUCC_INDEX(heap_listp))), bp);//修改heap_listp的后继的前驱为本节点//PUT(PRED_INDEX(bp), heap_listp);//本节点的前驱为heap_listp//PUT(SUCC_INDEX(heap_listp), bp);//头指针的后继修改coalesce(bp);//printf("退出mm_free\n");
}
/** mm_realloc - Implemented simply in terms of mm_malloc and mm_free*/
void *mm_realloc(void *ptr, size_t size){//printf("进入mm_realloc\n");void *newptr;size_t oldsize = GET_SIZE(HDRP(ptr));if(ptr==NULL){//printf("退出mm_realloc_1\n");return mm_malloc(size);}if(oldsize == size){//printf("退出mm_realloc_2\n");return ptr; }if(size == 0){mm_free(ptr);//printf("退出mm_realloc_3\n");return NULL;}if(!(newptr = mm_malloc(size))){//printf("退出mm_realloc_4\n");return NULL;}if(size < oldsize)oldsize = size;memcpy(newptr, ptr, oldsize);mm_free(ptr);//printf("退出mm_realloc_5\n");return newptr;}
static void* addlist(void *bp){//新的空闲块,foot和head已经填写完,需要在逻辑上挂到heap_listp后面//printf("进入addlist\n");unsigned int succ_num;//bp的前驱为heap_listpPUT(PRED_INDEX(bp), heap_listp);//bp的后继为原heap_listp的后继PUT(SUCC_INDEX(bp), GET(SUCC_INDEX(heap_listp)));//第一次运行时,heap_listp中的NULL后继就被继承到这个节点上//原heap_listp后继的前驱为bpif((succ_num = GET(SUCC_INDEX(heap_listp)))!=NULL)PUT(PRED_INDEX(succ_num), bp);//heap_listp的后继为bpPUT(SUCC_INDEX(heap_listp), bp);//printf("退出addlist\n");return bp;
}
static void *coalesce(void *bp){//物理上相邻的将其变为逻辑上相邻//1.断掉物理上的所有块的逻辑上前后的指针//2.逻辑上其前驱后继更新。(addlist)//PREV_BLKP(bp)->GET(PRED_INDEX(bp))//NEXT_BLKP(bp)->GET(SUCC_INDEX(bp))//printf("进入coalesce\n");size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp)));//物理上的前驱size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));//物理上的后继,不能用foot来求,因为结尾快没有footsize_t size = GET_SIZE(FTRP(bp));void *bp1,*bp2,*bp3;//printf("%d\t%d\t\n",prev_alloc, next_alloc);if(prev_alloc && next_alloc){//case 1:两边都在用PUT(SUCC_INDEX(bp), NULL);PUT(PRED_INDEX(bp), NULL);//printf("退出coalesce\n");}else if(prev_alloc && !next_alloc){//case 2:下面空闲块//printf("qk2\n");bp1 = bp;bp2 = NEXT_BLKP(bp);size += (GET_SIZE(HDRP(bp2)));//这里是物理上将其相邻,逻辑上需要加pred和succ指针在addlist中PUT(HDRP(bp), PACK(size, 0));PUT(FTRP(bp), PACK(size, 0));//这里的目的是断开逻辑上的块//第一块前驱的后继//PUT(SUCC_INDEX(GET(PRED_INDEX(bp1))), GET(SUCC_INDEX(bp1)));//第一块后继的前驱//PUT(PRED_INDEX(GET(SUCC_INDEX(bp1))), GET(PRED_INDEX(bp1)));//第二块前驱的后继PUT(SUCC_INDEX(GET(PRED_INDEX(bp2))), GET(SUCC_INDEX(bp2)));//第二块后继的前驱if(GET(SUCC_INDEX(bp2))!=NULL)PUT(PRED_INDEX(GET(SUCC_INDEX(bp2))), GET(PRED_INDEX(bp2)));PUT(SUCC_INDEX(bp), NULL);PUT(PRED_INDEX(bp), NULL);}else if(!prev_alloc && next_alloc){//case 3:上面空闲块//printf("qk3\n");bp1 = PREV_BLKP(bp);bp2 = bp;size += (GET_SIZE(HDRP(bp1)));PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));PUT(FTRP(bp), PACK(size, 0));//第一块前驱的后继PUT(SUCC_INDEX(GET(PRED_INDEX(bp1))), GET(SUCC_INDEX(bp1)));//第一块后继的前驱if((GET(SUCC_INDEX(bp1)))!=NULL)//如果他没有后继(链表最后一块)则啥也不用管PUT(PRED_INDEX(GET(SUCC_INDEX(bp1))), GET(PRED_INDEX(bp1)));//第二块前驱的后继//PUT(SUCC_INDEX(GET(PRED_INDEX(bp2))), GET(SUCC_INDEX(bp2)));//第二块后继的前驱//PUT(PRED_INDEX(GET(SUCC_INDEX(bp2))), GET(PRED_INDEX(bp2)));bp = bp1;PUT(SUCC_INDEX(bp), NULL);PUT(PRED_INDEX(bp), NULL);}else {//case 4:两边都空闲块//printf("qk4\n");void *bp1 = PREV_BLKP(bp);//第一块void *bp2 = bp;//第二块void *bp3 = NEXT_BLKP(bp);//第三块
size += (GET_SIZE(HDRP(bp1)) + GET_SIZE(HDRP(bp3)));PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0));PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0));//第一块前驱的后继PUT(SUCC_INDEX(GET(PRED_INDEX(bp1))), GET(SUCC_INDEX(bp1)));
//第一块后继的前驱if((GET(SUCC_INDEX(bp1)))!=NULL)PUT(PRED_INDEX(GET(SUCC_INDEX(bp1))), GET(PRED_INDEX(bp1)));//第二块前驱的后继//PUT(SUCC_INDEX(GET(PRED_INDEX(bp2))), GET(SUCC_INDEX(bp2)));//第二块后继的前驱//PUT(PRED_INDEX(GET(SUCC_INDEX(bp2))), GET(PRED_INDEX(bp2)));//第三块前驱的后继PUT(SUCC_INDEX(GET(PRED_INDEX(bp3))), GET(SUCC_INDEX(bp3)));//第三块后继的前驱if((GET(SUCC_INDEX(bp3)))!=NULL)PUT(PRED_INDEX(GET(SUCC_INDEX(bp3))), GET(PRED_INDEX(bp3)));bp = bp1;PUT(SUCC_INDEX(bp), NULL);PUT(PRED_INDEX(bp), NULL);}//printf("退出coalesce\n");return addlist(bp);
}
static void place(void *bp, size_t asize){//printf("进入place\n");size_t size = GET_SIZE(HDRP(bp));void *new_bp;if((size - asize) >= (2*DSIZE)){//剩下的空间足以构成一个最小块了。//printf("qka\n");PUT(HDRP(bp), PACK(asize, 1));PUT(FTRP(bp), PACK(asize, 1));new_bp = NEXT_BLKP(bp);//根据长度,分割块PUT(HDRP(new_bp), PACK(size - asize, 0));PUT(FTRP(new_bp), PACK(size - asize, 0));
PUT(PRED_INDEX(new_bp), GET(PRED_INDEX(bp)));//余下空闲部分的前驱为原本的前驱PUT(SUCC_INDEX(new_bp), GET(SUCC_INDEX(bp)));//余下空闲部分的后继为原本的后继PUT(SUCC_INDEX(GET(PRED_INDEX(bp))), new_bp);//前驱空闲快的后继为新bpif((GET(SUCC_INDEX(bp)))!=NULL)PUT(PRED_INDEX(GET(SUCC_INDEX(bp))), new_bp);//后继空闲快的前驱为新bpbp = new_bp;}else{//化为内部碎片 //printf("qkb\n");if(GET(SUCC_INDEX(bp))!=NULL)PUT(PRED_INDEX(GET(SUCC_INDEX(bp))), GET(PRED_INDEX(bp)));//修改后继的前驱(后继空闲快的前驱为自己的前驱)PUT(SUCC_INDEX(GET(PRED_INDEX(bp))), GET(SUCC_INDEX(bp)));//修改前驱的后继(前驱空闲快的后继为自己的后继)/如果此节点后继为NULL即,空闲链表自后一个节点,则这个节点的后继NULL则被逻辑上的pred节点继承PUT(HDRP(bp), PACK(size, 1));PUT(FTRP(bp), PACK(size, 1));}//printf("退出place\n");
}
static void *find_fit(size_t asize){//首次适配//printf("进入find_fit\n");void *bp;for(bp = heap_listp; bp&&(GET_SIZE(HDRP(bp)) > 0); bp = GET(SUCC_INDEX(bp))){if((!GET_ALLOC(HDRP(bp))) && (GET_SIZE(HDRP(bp)) >= asize)){//printf("退出find_fit_1\n");return bp;}}//printf("退出find_fir_2\n");return NULL;
}
static void *best_fit(size_t asize){//printf("进入best_fit\n");void *bp;size_t min_size, size;void *best_bp = NULL;int flag = 1;for(bp = heap_listp; bp&&(size = GET_SIZE(HDRP(bp))) > 0;bp = GET(SUCC_INDEX(bp))){//printf("bp:%u\t%u\tsucc:%u\tpred:%u\n",bp,GET(bp),GET(SUCC_INDEX(bp)), GET(PRED_INDEX(bp)));if((!GET_ALLOC(HDRP(bp))) && (size >= asize)){if(flag == 1){min_size = size;best_bp = bp;flag = 0;continue;}if(size < min_size){min_size = size;best_bp = bp;}}}//printf("退出best_fit\n");return best_bp;
}
重要函数、变量以及思路和注意点
重要函数、变量
static char *heap_listp
static void *extend_heap(size_t words)
static void *coalesce(void *bp)
static void place(void *bp, size_t asize)
static void *find_fit(size_t asize)
static void *best_fit(size_t asize)
static void* addlist(void *bp);//将合并的链表新增到头
注意点:
相较于上一个算法其改进点为,上一个算法的遍历方式是物理上临近的方式从一个遍历到下一个的,然后在判断是不是空闲的块。而这个算法管理空闲块的方式是通过succ
和pred
指针,即逻辑上的相连在常数时间内可以寻找到下一个空闲块。然后另一个不同是heap_listp
所在块的大小为2*DSIZE
也就是空闲链表的头指针为heap_listp
。
思路:
int mm_init(void)
申请6个WSIZE
,一W头,4W序言块,1W结尾块,初始的头指针的SUCC和PRED都为NULL,我一开始是将其指向了结尾块,结尾块也申请了4W的空间来放SUCC和PRED发现写完逻辑十分混乱,无法达到统一逻辑的情况,必须得考虑特殊地方。(也有可能当时存在其他BUG导致的)static void *extend_heap(size_t words)
与上一个算法相似,无特别改变之处。void *mm_malloc(size_t size)
这个函数的bug困扰我几天之久,当时使用./mdriver -t traces -V
测试时一共10个文件前4个文件会发生分配空间越界问题,后面的没有问题,重复查看逻辑了很多次,没有发现问题,于是最后想到和前面算法的代码进行对比,发现if(size < DSIZE)
部分我写成了if(size < 2*DSIZE)
,至今我也没搞清楚为啥吧2去掉就可以了。这个逻辑与上面算法一致。void mm_free(void *bp)
逻辑一致void *mm_realloc(void *ptr, size_t size)
逻辑一致static void* addlist(void *bp)
将新申请的空闲块挂到heap_listp
的后面,要考虑原heap_listp
的后继为NULL
的问题。其余的就是将SUCC
和PRED
按顺序改变。static void *coalesce(void *bp)
逻辑上可能会很混乱的函数,注意在这个函数中要合并的是物理上相邻的块,断开和改变的是逻辑上的块,断开是将相邻的空闲块(已经在空闲链表的某个位置)将其与其前驱后继断开,然后物理上合并(改变foot和head),然后挂到heap_listp后面。注意后继可能为NULL问题,可能会导致段错误。static void place(void *bp, size_t asize)
逻辑与上一个算法一致,只是需要在新出现的空闲块里,赋给其新的SUCC和PRED值。化为内部碎片情况时,需要概念其原本的前驱后继。static void *best_fit(size_t asize)
终止寻找的条件改为bp
值为NULL
,即到达空闲链表尾部
结果:
隐式空闲链表+最佳匹配
Results for mm malloc:
trace valid util ops secs Kops0 yes 99% 5694 0.008530 6681 yes 99% 5848 0.007493 7812 yes 99% 6648 0.011497 5783 yes 100% 5380 0.008861 6074 yes 66% 14400 0.000213 676695 yes 96% 4800 0.014915 3226 yes 95% 4800 0.013938 3447 yes 55% 12000 0.158764 768 yes 51% 24000 0.281268 859 yes 31% 14401 0.153106 94
10 yes 30% 14401 0.002869 5020
Total 75% 112372 0.661453 170
Perf index = 45 (util) + 11 (thru) = 56/100
显式空闲链表+最佳匹配+LIFO
Results for mm malloc:
trace valid util ops secs Kops0 yes 99% 5694 0.000194 293811 yes 99% 5848 0.000192 304272 yes 99% 6648 0.000224 296523 yes 100% 5380 0.000257 209014 yes 66% 14400 0.000161 891645 yes 96% 4800 0.002751 17456 yes 95% 4800 0.002706 17747 yes 55% 12000 0.025049 4798 yes 51% 24000 0.073440 3279 yes 31% 14401 0.147296 98
10 yes 30% 14401 0.002728 5278
Total 75% 112372 0.254998 441
Perf index = 45 (util) + 29 (thru) = 74/100
参考:
https://zhuanlan.zhihu.com/p/126341872 这位大佬的思路是我的+分离空闲链表。写的十分详细。膜拜^_^
CSAPP:MallocLab相关推荐
- CSAPP(CMU 15-213):Lab6 Malloclab详解
# 前言 本系列文章意在记录答主学习CSAPP Lab的过程,也旨在可以帮助后人一二,欢迎大家指正! tips:本lab主要是为了体验应用程序如何使用和管理虚拟内存,写一个动态存储分配器(dynami ...
- malloclab 实验详解(动态分配器如何设计)
本文主要针对CSAPP中的动态内存分配器做一个讲解,在讲解书上的各种分配器如何设计的同时,用实验的实际代码来实现这些算法. 首先,先贴上书本配套实验的地址:http://csapp.cs.cmu.ed ...
- 深入理解计算机系统(CSAPP)含lab详解 完结
文章目录 深入理解计算机操作系统-第一章 1.1 信息就是位 + 上下文 1.2 程序被其他程序翻译成不同的格式 1.3 了解编译系统如何工作是大有益处的 1.4 处理器读并解释储存在内存中的指令 1 ...
- 《深入理解计算机系统》(CSAPP)实验七 —— Malloc Lab
文章目录 隐式空闲链表 分离的空闲链表 显示空闲链表 1. 实验目的 2. 背景知识 3. Implicit list mm_init extend_heap mm_malloc find_fit p ...
- csapp 、sicp 、深入理解计算机系统、 计算机程序的构造和解释
CSAPP 第一版的英文版 深入理解计算机系统第一版中文版 这个是csdn账号 这里上传文件大小在10M以内 这个pdf是19+M的 深入理解计算机系统第二版的中文版下载 第一版英文版的介绍原书 ...
- CSAPP第五章就在“扯淡”!
"你的时间有限,所以不要为别人而活.不要被教条所限,不要活在别人的观念里.不要让别人的意见左右自己内心的声音.最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实 ...
- csapp:无符号数可能造成的程序bug
出自csapp练习2.26 size_t strlen(const char *s); int strloner(char *s,char *t) {return strlen(s)-strlen(t ...
- 链接器(linker)的作用——CSAPP第7章读书笔记
首先说说我为什么要去读这一章.这个学期开OS的课,在Morden Operating System上读到和Process有关的内容时看到这样一句话:"Process is fundament ...
- CSAPP:第三章程序的机器级表示1
CSAPP:程序的机器级表示1 关键点:数据格式.操作数指示符. 数据格式访问信息操作数指示符举例说明 数据格式 术语字(word)表示16位数据类型,32位数为双字(double words), ...
最新文章
- 985博士《深度学习》手推公式笔记开源PDF下载!
- 最古老的100个.com域名
- 构建Hadoop伪分布式环境
- 条件队列大法好:wait和notify的基本语义
- Hadoop:eclipse配置hadoop-eclipse-plugin(版本hadoop2.7.3)
- windows python3.7安装numpy问题的解决方法
- SAP OData的CSRF token在ABAP Netweaver服务器上是怎么生成的
- Web内容管理系统 Magnolia 启程-挖掘优良的架构(3)
- codeforce 227D Naughty Stone Piles (贪心+递归+递推)
- 打造自己Django博客日记
- ORACLE专有模式与共享模式
- 易语言调用大漠插件判断游戏是否在线
- 【笔记】分布式网络与分布式账本
- Python数据分析与机器学习27-拼写纠正实例
- 【Excel文件合并工具】
- Windows7下安装sql2000个人版(可用,本人已测)
- Oracle 官网共享账号
- Junit5 单元测试框架的使用
- Airflow实战--获取REST参数并通过Xcom传递给Bash算子
- 《用户体验要素——以用户为中心的产品设计》读书笔记