#CSAPP:malloclab
CSAPP:9.9.12
针对空闲块的组织方法有以下三种:
- a.隐式空闲链表(implicit free list)
- b.显式空闲链表(explicit free list)
- c.分离空闲链表(segregated free list)
查找空闲块的三个方法:
- a.首次适应(first fit)
- b.最佳适配(best fit)
- c.下一次适配(next fit)
- d.分离适配,特殊情况包括伙伴系统,优点在于快速搜索和快速合并(大小相同,地址连续)。
方案一:隐式空闲链表+first fit/next fit
- 初始化堆 —— mm_init函数
mm_init步骤如下:
首先在堆上分配16个字节,包括4字节对齐块,8字节序言块,4字节结尾块。
调extend_heap扩展堆,创建初始的空闲块,大小为4096字节。
- 扩展堆 —— extend_heap函数
函数原型: static void *extend_heap(size_t words);
以下两种场景需要扩展堆:
调用mm_init初始化堆时。
调用mm_malloc找不到合适的空闲块时。
- 释放和合并块 —— mm_free和coalesce函数
调用mm_free释放块,步骤如下:
将当前块的头部和脚部中的分配位清零。
将这个块与它邻接的前后空闲块进行合并,采用立即合并策略。
调用coalesce合并前后的合并块,原型:static void *coalesce(void *bp);,分四种情况:
情况1:前面的块和后面的块都已分配 —— 不可能合并,简单返回bp即可。
情况2:前面的块已分配,后面的块空闲 —— 用当前块和后面块的大小之和更新当前块的头部和后面块的脚部。返回bp
情况3:前面的块是空闲的,后面的块是分配的 —— 用两块大小之和更新前面块的头部和后面块的脚部。返回PREV_BLKP(bp)
情况4:前面和后面的块都是空闲的 —— 用三个块大小之和更新前面块的头部和后面块的脚部。返回PREV_BLKP(bp)
https://blog.csdn.net/pcj_888/article/details/108812886
#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) */
""
};
static char *heap_listp;
#define WSIZE 4 /* Word and header/footer size (bytes) */
#define DSIZE 8 /* Double word size (bytes) */
#define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/* Pack a size and allocated bit into word */
#define PACK(size, alloc) ((size) | (alloc))
/* Read and write a word at address p */
#define GET(p) (*(unsigned int *)(p))
#define PUT(p, val) (*(unsigned int *)(p) = (val))
/* Read the size and allocated fields from address p */
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)// 判断这个块是否已分配
/* Given block ptr bp, compute address of its header and footer */
#define HDRP(bp) ((char *)(bp) - WSIZE)
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)
/* Given block ptr bp, compute address of next and previous blocks */
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE)))
#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE)))
/* Globe var */
static char *heap_listp;
/* 函数声明 */
static void *extend_heap(size_t words);
static void *coalesce(void *bp);
static void *find_fit(size_t asize);
/* 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)))
/*
* 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);
if(extend_heap(CHUNKSIZE/WSIZE)==NULL)
return -1;
return 0;
}
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);
}
void place(void *bp,size_t asize){
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));
}
else{
PUT(HDRP(bp),PACK(csize,1));
PUT(FTRP(bp),PACK(csize,1));
}
}
/*
* 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;
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;
}
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))&&(asize<=GET_SIZE(HDRP(bp)))){
//寻找第一个可以匹配的块
//heap_listp = bp; //next_fit,每次让它指向最后分配的位置就好,下次从这里匹配
return bp;
}
}
return NULL;
}
/*
* 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);
}
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);
}
return bp;
}
/*
* 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 copySize;
newptr = mm_malloc(size);
if (newptr == NULL)
return NULL;
copySize = *(size_t *)((char *)oldptr - SIZE_T_SIZE);
if (size < copySize)
copySize = size;
memcpy(newptr, oldptr, copySize);
mm_free(oldptr);
return newptr;
}