/*
* mm-explicit link list.c - The fastest, highest memory-efficient malloc package I think of.
*
* In this approach, a block is allocated by simply incrementing
* the brk pointer.
* 空闲块组织成双向链表,并按块的大小升序排列,首块的prev指向尾块,但尾块的next为NULL作为空闲链表的边界
* malloc分配策略使用First Fit策略,保证最大内存利用率,而新分配一个块的时间需要o(k),k:空闲块的数量,
* 而释放能够在常数时间内完成
* Realloc is implemented directly using mm_malloc and mm_free.
*
* 31 30 29 28 ....... 3 2 1 0
* +-----4B-------|------4B----------|--------4B--------|---------------------------------+
* | | | | | unused | 1/0 | 1/0 | |
* +--------------------------------------------------------------------------------------+
* | |
* 表示前面一个块是否为allocated(1)<==+ |
* 表示此块是否为allocated <===========+
*
*
*
*
* 1)空闲块
* +-----4B-----|----4B-----|----4B----|---size meet alignment requs----------|---4B-----+
* | header | prev | next | payload | footer |
* +--------------------------------------------------------------------------------------+
*空闲块有两种状态:a)在explicit link list; b)Suspended (Read to operate such as Delete. )
*
* 2)分配块
* +-----4B--------|-----------------------------------------------------------------------+
* | header | payload |
* +---------------------------------------------------------------------------------------+
*
* origin head
* +--------|--------|--------|--------------------------------------------|---------|
* | 0 | 8/(1,1) 8/(1,1)| header| prev | next | payload | footer|0/(1,0/1)|
* +--------|--------|--------|--------------------------------------------|---------|
* prologue first block epilogue
*
* 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 */
"Shakspear",
/* First member's full name */
"June Eleventh",
/* First member's email address */
"1569496189@qq.com",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""
};
/* Varibals 之前用(void *)而非(char*) */
static char *heap_listp;
static char *first_freeblock;
/* 宏 */
//#define DEBUG
// 想要打印出来的地方加上这个:
/*
*
#ifdef DEBUG
mm_check(__FUNCTION__);
#endif // DEBUG
*
*/
/* 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 by myself*/
#define WSIZE 4
#define DSIZE 8
//#define LEN_PTR sizeof(void *)
#define CHUNKSIZE (1<<12) //4K
//#define MINIBLK_SIZE (DSIZE+2*LEN_PTR)
#define MINIBLK_SIZE 16
#define MAX(x, y) (x>y?x;y)
/* pack a size allocated bit and the previous block allocated bit into a word */
#define PACK(size, alloc, prev_alloc) ((size) | alloc | (prev_alloc << 1))
/* GET获取数据,PUT写入数据 */
#define GET(p) (*(unsigned int *)(p))
#define PUT(p, val) (*(unsigned int *)(p) = val)
/* read the size and allocated fileds from address p */
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)
#define GET_PREVALLOC(p) ((GET(p) & 0x2) >> 1)
/* Given the 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 the block ptr bp, compute address of its previous and next blocks in adjacent address */
#define NEXT_BLKP(bp) ((char *)bp + GET_SIZE(HDRP(bp)))
#define PREV_BLKP(bp) ((char *)bp - GET_SIZE(HDRP(bp) - WSIZE)) /* Only the previous block is free */
/* 通过链表链接的空闲块 */
/* Given the block ptr bp, compute fields address of its previous ptr and next ptr */
/* 指向bp的prev域和next域 Very important */
/* 何不用64位长的long int 来记录地址呢? interesting! I found out the length of the block address will not exceed 32 bits */
// #define LINKPREV_BLKP(bp) (*(char **)bp) //分辨不出内存里是指针还是数值
// #define LINKNEXT_BLKP(bp) (*((char **)(bp) + LEN_PTR))
#define LINKPREV_BLKP(bp) ((char *)bp) //指向该块的next域和prev域
#define LINKNEXT_BLKP(bp) ((char *)(bp) + WSIZE)
/* 函数原型 */
static void place(void *bp, size_t asize);
static void *Whole_Coalesce(size_t size);
static void *find_fit(size_t asize);
static void *Coalesce(void *bp);
static void *Delete( void *bp);
static void Insert(void *insert_startp, void* bp );
static void *extend_heap(size_t words);
static void SET_NEXTBLKP_PREVALLOC(char *bp, size_t val);
int mm_check(char *func);
/* 若返回0 代表检查出错 */
int mm_check(char *func){
char *ep=first_freeblock;
char *start=(void *)mem_heap_lo(), *end=(void *)mem_heap_hi();
printf("\t堆的范围是:[ 0x%x ======> 0x%x] \n", start, end);
/* 检查list是否为空 */
/*
if(first_freeblock == NULL)
printf("free list state: Empty Empty Empty!\n");
else
printf("free list state: existed existed existed!\n");
*/
/* 1.查看free list 中的块的prev和next域是否都在堆中 */
for(ep=first_freeblock; ep!=NULL; ep=(char *)GET(LINKNEXT_BLKP(ep))){
/* 若标记位为1,代表出错 */
if( (long)GET(LINKPREV_BLKP(ep)) < (long)start || (long)GET(LINKPREV_BLKP(ep)) > (long)end) {
printf("*** *** 空闲链表中的块的prev域出错, 不在堆范围内!\n");
printf("该块的地址为:0x%x\n",ep);
return 0;
}
if( (char *)GET(LINKNEXT_BLKP(ep)) != NULL
&&((long)GET(LINKNEXT_BLKP(ep))<(long)start || (long)GET(LINKNEXT_BLKP(ep))> (long)end)){
printf("*** *** 空闲链表中的块的next域出错, 不在堆范围内!\n");
printf("该块的地址为:0x%x\n",ep);
return 0;
}
if( (char *)GET(LINKNEXT_BLKP(ep)) == ep) {
printf("*** *** 空闲链表中的块的next域出错, 指向了自己!\t");
printf("该块的地址为:0x%x\n",ep);
return 0;
}
}
/* 2.查看堆中所有块块的PREV_ALLOC位是否和前面的块的分配位一致 */
for(ep=first_freeblock; (long)ep < (long)((long)end -3); ep=(char *)NEXT_BLKP(ep) ){
/* 若标记位为1,代表出错 */
if( GET_ALLOC(HDRP(ep)) != GET_PREVALLOC(HDRP(NEXT_BLKP(ep))) ) {
printf("*** *** 空闲链表中的块 ALLOC标记与后一块的PREV_ALLOC位矛盾!\n");
printf("该块的地址为:0x%x, ALLOC:%d\n",ep, GET_ALLOC(HDRP(ep)) );
printf("后块的地址为:0x%x, PREV_ALLOC:%d \n\n",NEXT_BLKP(ep), GET_PREVALLOC(HDRP(NEXT_BLKP(ep))) );
return 0;
}
}
/* 3.检查空闲链表中的块是否都是被标记成0(free) */
for(ep=first_freeblock; ep!=NULL; ep=(char *)GET(LINKNEXT_BLKP(ep))){
/* 若标记位为1,代表出错 */
if( GET_ALLOC(HDRP(ep)) ) {
printf("*** *** 空闲链表中的块 ALLOC标记位出错, 应该为0!\n");
printf("该块的地址为:0x%x\n",ep);
return 0;
}
}
/* 4.检查相邻的块是否都已经合并 */
// for(ep=first_freeblock; ep!=NULL; ep=(char *)GET(LINKNEXT_BLKP(ep))){
// if(GET_ALLOC(HDRP(NEXT_BLKP(ep))) || GET_PREVALLOC(HDRP(ep))){
// printf("存在没有合并的相邻块!\n");
// return 0;
// }
/* 检查所有块的地址是否满足8字节对齐
* 前提堆已经初始化,所以在mm_init中不能使用mm_check
*/
for(ep=heap_listp + DSIZE; GET_SIZE(HDRP(ep))!=0; ep=(char *)NEXT_BLKP(ep)){
if( (long)ep%8 != 0){
printf("块的有效载荷开始地址 没有8字节对齐\n");
return 0;
}
}
return 1;
}
/* void place(size_t words) ------------------------ begin------------------- */
/* in list ==> suspended ==> allocated + (opntional:in list)
* 带有分配(allocated)能力,但不合并 不合并 不合并
* 要求asize考虑了对齐和头尾长度
*/
static void place(void *bp, size_t asize)
{
#ifdef DEBUG
printf(" ====> place(bp=0x%x, asize=%x)\n",bp, asize);
mm_check(__FUNCTION__);
#endif // DEBUG
size_t size = GET_SIZE(HDRP(bp));
/* 1.统一处理:拆除逻辑链接 */
Delete(bp);
if(size < asize){
fprintf(stderr, "*** *** place error!该块本身大小(0x%x)小于待分配值(0x%x)s*** *** ****\n\n", size, asize);
}
/* 分割后的大小满足最小快的要求 */
if((size - asize) >= MINIBLK_SIZE){
/* 分割后first block */
PUT(HDRP(bp), PACK(asize, 1, GET_PREVALLOC(HDRP(bp)))) ; //Header
PUT(FTRP(bp), PACK(asize, 1, GET_PREVALLOC(HDRP(bp)))) ; //footer
/* 分割后的last block */
PUT(HDRP(NEXT_BLKP(bp)), PACK(size - asize, 0, 1)) ; //Header
PUT(FTRP(NEXT_BLKP(bp)), PACK(size - asize, 0, 1)) ; //footer
/* 将此块的下一个块的prev_alloc不用进行设置,因为本来就为0(free) */
/* 将分离后的last block 插入list */
Insert(NULL, NEXT_BLKP(bp)); //与空闲块的数量成线性关系
#ifdef DEBUG
printf(" <==== place() 分割完成,被分离剩下的块地址_bp:0x%x, 大小:0x%x\n", NEXT_BLKP(bp), GET_SIZE(HDRP(NEXT_BLKP(bp))));
#endif // DEBUG
return ;
// SET_NEXTBLKP_PREVALLOC(NEXT_BLKP(bp), 0);
}else{
/* 不需要分割 */
PUT(HDRP(bp), PACK(GET_SIZE(HDRP(bp)), 1, GET_PREVALLOC(HDRP(bp)))); //header
PUT(FTRP(bp), PACK(GET_SIZE(HDRP(bp)), 1, GET_PREVALLOC(HDRP(bp)))); //Footer
SET_NEXTBLKP_PREVALLOC(bp, 1); /* 将此块的下一个块的prev_alloc进行设置 */
#ifdef DEBUG
printf(" <==== place\n");
printf("此块不需要分割\n\n\n ");
#endif // DEBUG
return ;
}
}
/* void place(size_t words) -------------------- end -------------------------- */
/* void *Whole_Coalesce( asize) ----- begin--------- */
/* 空闲表不能提供适当大小的空闲块时调用此函数
* 边搜索边合并空闲块,return NULL if not find a proper free block
*/
static void *Whole_Coalesce(size_t size){
#ifdef DEBUG
printf(" ====> Whole_Coalesce(size:0x%x)\n", size);
mm_check(__FUNCTION__);
#endif // DEBUG
char *bp = first_freeblock;
/* case 1)list is empty */
if(first_freeblock == NULL){
#ifdef DEBUG
mm_check(__FUNCTION__);
printf(" <==== Whole_coalesce发现free list为空\n\n\n");
#endif // DEBUG
return NULL;
}
/* case 2)list isn't empty */
while((void *)GET(LINKNEXT_BLKP(bp)) != NULL){ /* 遍历list */
if(!GET_PREVALLOC(HDRP(bp)) || !GET_ALLOC(HDRP(NEXT_BLKP(bp))) ){ //该块可进行合并
bp = Coalesce(bp);
if(GET_SIZE(HDRP(bp)) >= size)
#ifdef DEBUG
printf(" <==== Whole_coalesce找到bp:0x%x,size:0x%x\n\n\n",bp ,size);
#endif // DEBUG
return (void *)bp;
}else{
/* 迭代 */
bp = (void *)GET(LINKNEXT_BLKP(bp));
}
}
#ifdef DEBUG
printf(" <==== Whole_coalesce()未能找到0x%x 大小空间\n\n\n", size);
#endif // DEBUG
return NULL;
}
/* void *Whole_Coalesce( asize) ----- end --------- */
/* void *find_fit( asize) ----- begin--------- */
/* in list ==> in list 从list里面找出来一个大小合适的空闲块
*/
static void *find_fit(size_t asize){
#ifdef DEBUG
fprintf(stderr,"===> find_fit(asize:0x%x)\n", asize);
mm_check(__FUNCTION__);
#endif // DEBUG
char *bp = first_freeblock;
for( ; bp != NULL; bp = (char *)GET(LINKNEXT_BLKP(bp))){
if(GET_SIZE(HDRP(bp)) >= asize){
#ifdef DEBUG
fprintf(stderr," <==== find_fit()成功, 地址bp:0x%x 需要的asize:0x%x\n\n\n",bp, asize);
#endif // DEBUG
return (void *)bp;
}
}
#ifdef DEBUG
fprintf(stderr," <==== find_fit未能找到合适的位置\n\n\n");
#endif // DEBUG
return NULL;
}
/* void *find_fit( asize)) ----- end --------- */
/* void *Coalesce( bp) ----- begin--------- */
/* in list ==> in list Don‘t need "SET_NEXTBLKP_PREVALLOC"
* 有多个Delete()语句时,先删除size小的,后删除大的
* 必须记录最后一个Delete返回值,因为它才是有效的
* 一次合并,不像核裂变一样持续进行
*/
static void *Coalesce(void *bp){
char *start=(void *)mem_heap_lo(), *end=(void *)mem_heap_hi();
#ifdef DEBUG
printf(" ====> Coalesce(bp:0x%x)\n", bp);
if(bp >= end || bp < start)
printf("bp jumped the boundry of the heap!\n");
mm_check(__FUNCTION__);
#endif // DEBUG
size_t prev_alloc = GET_PREVALLOC(HDRP(bp));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t new_prev_alloc; // 放置合并后的新块的PREV_ALLOC
char *insert_startp;
// 前提:前面一个块是free状态
size_t size_1 ;
size_t size_2 = GET_SIZE(HDRP(bp));
size_t size_3 ;
/* case 1)前后皆Alloc */
if( prev_alloc && next_alloc){
#ifdef DEBUG
printf(" <==== 无需合并,bp:0x%x\n\n\n", bp);
#endif // DEBUG
return bp;
}
/* case 2)前F 后A */
if( !prev_alloc && next_alloc)
{
size_1 = GET_SIZE(HDRP(PREV_BLKP(bp)));
if(size_1 > size_2){
Delete(bp);
insert_startp = Delete(PREV_BLKP(bp));
}else{
Delete(PREV_BLKP(bp));
insert_startp = Delete(bp);
}
/* 1.物理——修改前一个块的大小 */
// PREV_ALLOC要设置为前一个块的PREV_ALLOC
new_prev_alloc = GET_PREVALLOC(HDRP(PREV_BLKP((bp))));
PUT(HDRP(PREV_BLKP(bp)), PACK(size_1 + size_2, 0, new_prev_alloc));
PUT(FTRP(PREV_BLKP(bp)), PACK(size_1 + size_2, 0, new_prev_alloc));
/* 2.逻辑链接——还需要修改其一个块的指针 */
Insert(insert_startp, PREV_BLKP(bp) ); //request "Insert" not to "Coalesce"
#ifdef DEBUG
printf(" <==== Coalesce()仅与前一个块(0x%x)合并\n\n\n", PREV_BLKP(bp));
#endif // DEBUG
return PREV_BLKP(bp);
}
/* case 3)前A 后F */
if(prev_alloc && !next_alloc)
{
size_3 = GET_SIZE(HDRP(NEXT_BLKP(bp)));
if(size_2 > size_3){
Delete(NEXT_BLKP(bp));
insert_startp = Delete(bp);
}else{
Delete(bp);
insert_startp = Delete(NEXT_BLKP(bp));
}
/* 修改当前块大小 */ /* +---前面一个块为A */
PUT(HDRP(bp), PACK(size_2 + size_3, 0, 1));
PUT(FTRP(bp), PACK(size_2 + size_3, 0, 1));
Insert((void *)insert_startp, bp);
#ifdef DEBUG
printf(" <==== Coalesce()仅与后一个块(0x%x)合并\n\n\n", NEXT_BLKP(bp));
#endif // DEBUG
return bp;
}
/* case 4)F F F */
if(!prev_alloc && !next_alloc)
{
void *prev_bp = PREV_BLKP(bp);
void *next_bp = NEXT_BLKP(bp);
size_1 = GET_SIZE(HDRP(PREV_BLKP(bp)));
size_3 = GET_SIZE(HDRP(NEXT_BLKP(bp)));
// PREV_ALLOC要设置为前一个块的PREV_ALLOC
new_prev_alloc = GET_PREVALLOC(HDRP(prev_bp));
/* 确保尺寸最大的块最后删除 */
if(size_1 > size_2){
Delete(bp);
if(size_1 > size_3){
Delete(next_bp);
insert_startp = Delete(prev_bp);
}else{
Delete(prev_bp);
insert_startp = Delete(next_bp);
}
}else{
Delete(prev_bp);
if(size_2 > size_3){
Delete(next_bp);
insert_startp = Delete(bp);
}else{
Delete(bp);
insert_startp = Delete(next_bp);
}
}
/* 修改新块大小 */
PUT(HDRP(prev_bp), PACK(size_1 + size_2 +size_3, 0, new_prev_alloc) ); //header
PUT(FTRP(prev_bp), PACK(size_1 + size_2 +size_3, 0, new_prev_alloc) ); //footer
/* 插入到链表结构 suspended ==> in list */
Insert(insert_startp, prev_bp);
#ifdef DEBUG
printf(" <==== Coalesce()与前(0x%x)后(0x%x)两个块合并\n\n\n", prev_bp, next_bp);
#endif // DEBUG
return prev_bp;
}
}
/* void *Coalesce( bp) ----- end--------- */
/* void *Delete( bp) ----- begin--------- */
/* in list ==> suspended (alloc bit任)
* 没有更改malloc bit
* 返回被删除块的前一个块的地址,提高Insert插入速度
* 若返回NULL,说明删除的是链表第一个元素
* 可能出错的情况:空闲块链表为空,仍调用了Delete. 我尽量取避免,delete在coalese中,
*/
static void *Delete(void *bp){
char *next_bp, *prev_bp;
size_t alloc=GET_ALLOC(HDRP(bp));
#ifdef DEBUG
printf(" ====> Delete(bp:0x%x)\n", bp);
mm_check(__FUNCTION__);
if(alloc){
printf("*** *** Delete Error! Try to delete a allocated block!\n");
}
#endif // DEBUG
if(first_freeblock == NULL){
fprintf(stderr, "*** *** *** Delete error!\n\n\n");
}
/* case 1)list中仅有一个元素 */
if(bp == first_freeblock && (void *)GET(LINKNEXT_BLKP(bp)) == NULL){
//后块 视 前块suspended状态为allcated
SET_NEXTBLKP_PREVALLOC(bp, 1);
#ifdef DEBUG
printf(" <==== Delete list中仅有一个元素\n\n\n");
#endif // DEBUG
return first_freeblock = NULL;
}
/* case 2)删除list的队头,块的个数大于1 */
if(bp == first_freeblock){
//后块 视 前块suspended状态为allcated
SET_NEXTBLKP_PREVALLOC(bp, 1);
PUT(LINKPREV_BLKP((void *)GET(LINKNEXT_BLKP(bp))), (void *)GET(LINKPREV_BLKP(bp)));
first_freeblock = (char *)GET(LINKNEXT_BLKP(bp));
#ifdef DEBUG
printf(" <==== Delete 删除list的队头,块的个数大于1\n\n\n");
#endif // DEBUG
return NULL;
}
/* case 3)删除list的队尾,块的个数大于1 */
if((char *)GET(LINKNEXT_BLKP(bp)) == NULL){
//后块 视 前块suspended状态为allcated
SET_NEXTBLKP_PREVALLOC(bp, 1);
PUT(LINKNEXT_BLKP((char *)GET(LINKPREV_BLKP(bp))), NULL);
PUT(LINKPREV_BLKP(first_freeblock), (char *)GET(LINKPREV_BLKP(bp)));
#ifdef DEBUG
printf(" <==== Delete 删除list的队尾,块的个数大于1\n\n\n");
#endif // DEBUG
return (void *)(GET(LINKPREV_BLKP(bp)));
}
/* case 4)删除list中间的元素 */
//后块 视 前块suspended状态为allcated
SET_NEXTBLKP_PREVALLOC(bp, 1);
#ifdef DEBUG
printf(" Delete(bp:0x%x) case 4)删除list中间的元素 \n", bp);
mm_check(__FUNCTION__);
#endif // DEBUG
prev_bp = (char *)GET(LINKPREV_BLKP(bp));
next_bp = (char *)GET(LINKNEXT_BLKP(bp));
PUT(LINKNEXT_BLKP(prev_bp), next_bp);
PUT(LINKPREV_BLKP(next_bp), prev_bp);
#ifdef DEBUG
printf(" <==== Delete 删除list中间的元素\n\n\n");
#endif // DEBUG
return (void *)prev_bp;
}
/* void *Delete( bp) ----- end --------- */
/* void Insert( insert_startp, bp) ----- begin--------- */
/* suspended ==> in list
* Coalesce 禁止Insert进行合并
* 将suspended的alloc bit修改成0
* 若insert_startp 为null则从链表头开始插入
* 借助insert_startp指针方便在空闲链表快速插入bp(suspended)
*/
static void Insert(void *insert_startp, void* bp ){
char *start=(void *)mem_heap_lo(), *end=(void *)mem_heap_hi();
char *prev_bp, *ep; //ep: explore pointer
size_t need_size = GET_SIZE(HDRP(bp));
ep = insert_startp;
#ifdef DEBUG
printf(" ====> insert(insert_startp:0x%x, bp:0x%x)\n",insert_startp, bp);
mm_check(__FUNCTION__);
if( insert_startp != NULL && (insert_startp < start || insert_startp > end )) {
printf("Insert中insert_startp的地址不正确:不在堆范围内!\n");
}
#endif // DEBUG
/* 2.4 Error: insert_startp!=NULL && first_freeblock == NULL
* 链表不存在居然还有指针指向链表
*/
if(ep!=NULL && first_freeblock == NULL){
fprintf(stderr, "*** *** Insert Error:链表不存在居然还有指针指向链表\n");
exit(1);
}
/* 统一设置本块的alloc bit 为0 */
PUT(HDRP(bp), PACK(GET_SIZE(HDRP(bp)), 0, GET_PREVALLOC(HDRP(bp))));
PUT(FTRP(bp), PACK(GET_SIZE(HDRP(bp)), 0, GET_PREVALLOC(HDRP(bp))));
/* 2.1 原explicit list为空 */
if(first_freeblock == NULL && ep == NULL){
first_freeblock = bp;
PUT(LINKNEXT_BLKP(bp), NULL); /* 将bp插入空表,并做好双向链接 */
PUT(LINKPREV_BLKP(bp), bp);
SET_NEXTBLKP_PREVALLOC(bp, 0); //SET_Nextblock PREVALLOC
#ifdef DEBUG
printf(" <==== Insert; 原explicit free list为空\n\n\n");
#endif // DEBUG
return ;
}
/* now, first_freeblock ==> 非空 */
/* 2.2, 2.3原链表有1个或多个块,根据适当的位置来插入 */
/* 2.2 原链表仅有一个块 */
if(ep == NULL){
ep = first_freeblock;
}
/* 搜索被引上正道,寻找合适的插入位置,在ep前面插入,
* 要求ep后的块大小大于等于bp的块大小 */
while( ep!=NULL && GET_SIZE(HDRP(ep)) < need_size){
ep = (char *)GET(LINKNEXT_BLKP(ep)); //向后迭代
}
/* a)没有比bp大的块,bp需要插入到非空链表的表尾tail */
if(ep == NULL){
PUT(LINKPREV_BLKP(bp), (char *)GET(LINKPREV_BLKP(first_freeblock)));
PUT(LINKNEXT_BLKP((char *)GET(LINKPREV_BLKP(first_freeblock))), bp);
PUT(LINKNEXT_BLKP(bp), NULL);
PUT(LINKPREV_BLKP(first_freeblock), bp);
SET_NEXTBLKP_PREVALLOC(bp, 0); //SET_Nextblock PREVALLOC
#ifdef DEBUG
printf(" <==== Insert;bp(size:0x%x)插入到非空链表表尾\n\n\n", GET_SIZE(HDRP(bp)));
#endif // DEBUG
return ;
}
/* b)插入队头,无论空闲链表中有1个还是多个块 */
if(ep == first_freeblock){
PUT(LINKPREV_BLKP(bp), (char *)GET(LINKPREV_BLKP(first_freeblock)));
PUT(LINKNEXT_BLKP(bp), first_freeblock);
PUT(LINKPREV_BLKP(first_freeblock), bp);
first_freeblock = bp;
SET_NEXTBLKP_PREVALLOC(bp, 0); //SET_Nextblock PREVALLOC
#ifdef DEBUG
printf(" <==== Insert;bp(size:0x%x)插入非空链表队头\n\n\n", GET_SIZE(HDRP(bp)));
#endif // DEBUG
return ;
}
/* c)插入队中,i.e前后都有块照应 */
prev_bp = (char *)GET(LINKPREV_BLKP(ep));
PUT(LINKPREV_BLKP(ep), bp);
PUT(LINKNEXT_BLKP(bp), ep);
PUT(LINKNEXT_BLKP(prev_bp), bp);
PUT(LINKPREV_BLKP(bp), prev_bp);
SET_NEXTBLKP_PREVALLOC(bp, 0); //SET_Nextblock PREVALLOC
#ifdef DEBUG
printf(" <==== Insert;bp(size:0x%x)插入非空链表中间\n\n\n", GET_SIZE(HDRP(bp)));
#endif // DEBUG
return ;
}
/* void Insert( insert_startp, bp) ----- end --------- */
/* *extend_heap( words) ----- begin--------- */
/* 拓展堆words个字,以字为单位 suspended ==> in list
* 拓展要多少空间就分配多少空间,决不能打折,也不能合并!!
* 带有合并(coalesce)能力,这里拓展堆没有采用MAX(CHUNKSIZE,~)机制,看能否throuput better
*/
static void *extend_heap(size_t words)
{
char *bp, *heap_hi_bdy = (char *)mem_heap_hi() +1; //堆最大的地址加1
size_t size, prev_alloc= GET_PREVALLOC(HDRP(heap_hi_bdy));
/* 满足2字 alignment */
size = (words%2) ? (words+1)*WSIZE : words*WSIZE;
#ifdef DEBUG
printf(" ====> extend_heap(words:%u = 0x%x Byte)\n", words, words*WSIZE);
mm_check(__FUNCTION__);
#endif
/* 要多少空间就分配多少空间 */
if((long)(bp = mem_sbrk(size)) == -1)
return NULL;
/* 释放old结尾块,其成为suspended state */
PUT(HDRP(bp), PACK(size, 0, prev_alloc));
PUT(FTRP(bp), PACK(size, 0, prev_alloc));
/* 更新 新结尾块 */
PUT( HDRP(NEXT_BLKP(bp)), PACK(0, 1, 0)); //prev_alloc = 0;
/* 将准备待续的suspended块插入free list */
/*
*可能空间刚好用完==>first_freeblock可能为NULL
*if(first_freeblock == NULL)
* Insert( NULL, bp);
*else
* suspended块必定插入在free list的尾部
* Insert( (void *)GET(LINKPREV_BLKP(first_freeblock)), bp); //
*
*/
// 保守做法,从前面插入 时间复杂度高,与空闲块的数量成正比 ——可以提高、改进
Insert( NULL, bp);
#ifdef DEBUG
printf(" <==== extend_heap(); 返回值:0x%x\n\n\n", (void *)bp);
#endif
return (void *)bp;
}
/* *extend_heap() ----- end --------- */
/*
* mm_init - initialize the malloc package.
*/
int mm_init(void)
{
#ifdef DEBUG
printf(" ====> mm_init()\n");
#endif // DEBUG
char *bp;
if( (heap_listp = mem_sbrk(4 * WSIZE)) == (void *)-1 )
return -1;
PUT(heap_listp, 0); //Alignment padding
PUT(heap_listp + (1 * WSIZE), PACK(8, 1, 1)); //prologue header
PUT(heap_listp + (2 * WSIZE), PACK(8, 1, 1)); //prologue footer
PUT(heap_listp + (3 * WSIZE), PACK(0, 1, 1)); //epilogue
if(extend_heap(CHUNKSIZE/WSIZE) ==NULL ){
#ifdef DEBUG
printf("*** *** mm_init: Error! extend_heap()调用失败\n");
#endif // DEBUG
return -1;
}
heap_listp += DSIZE;
/* Set the first free block in the heap, and set link in the explicit link list */
first_freeblock = heap_listp + DSIZE;
bp = first_freeblock;
PUT(HDRP(bp), PACK(CHUNKSIZE, 0, 1 )); //SET first block header
PUT(FTRP(bp), PACK(CHUNKSIZE, 0, 1 )); //SET first block footer
PUT(LINKNEXT_BLKP(bp), NULL); //设置双向链表,prev指向自己,next指向NULL
PUT(LINKPREV_BLKP(bp), bp);
SET_NEXTBLKP_PREVALLOC(bp, 0);
#ifdef DEBUG
printf(" <==== mm_init(); fisrt_freeblock:0x%x\n\n\n", first_freeblock);
#endif // DEBUG
return 0;
}
/* mm_init() ------ end -------------- */
/*
* mm_malloc - Allocate a block by incrementing the brk pointer.
* Always allocate a block whose size is a multiple of the alignment.
* 返回的有效载荷必须8字节对齐,载荷大小也需要对齐才能保证前者
*/
void *mm_malloc(size_t size)
{
#ifdef DEBUG
printf(" ====> malloc(size:0x%x)\n\n\n", size);
mm_check(__FUNCTION__);
#endif // DEBUG
size_t newsize = ALIGN(size), prev_size, extend_size, epilogue_prevalloc;
//newsize还包括overhead,对齐
char *bp, *prev_bp, *heap_hi_bdy =(char *)mem_heap_hi() +1;
/* Ignore spuring request */
if(size == 0) {
return NULL;
}
/* 调整块大小,满足头部的开销和对齐要求 */
if(newsize <= MINIBLK_SIZE){ //最小块大小
newsize = MINIBLK_SIZE;
}
/* 第一次找到合适的块 */
if((bp = find_fit(newsize)) != NULL){
place(bp, newsize);
#ifdef DEBUG
printf(" <==== malloc(); 第一次找到合适的地址bp: 0x%x, 共0x%xBytes\n\n\n", bp, newsize);
#endif // DEBUG
return bp;
}
/* 第一次没找到,边合并边进行第二次查找 */
if((bp = Whole_Coalesce(newsize)) != NULL){
place(bp, newsize);
#ifdef DEBUG
printf(" <==== malloc(); 第二次寻找成功,返回地址bp: 0x%x, 共0x%xBytes\n\n\n", bp, newsize);
#endif // DEBUG
return bp;
}
/* 两次都没有找到 */
// epilogue_prevalloc = GET_PREVALLOC(HDRP((char *)mem_heap_hi() + 1) );
// /* 若结尾块的前一个块为free则可以减少此次申请的空间 */
// /* 直接考虑总大小 */
// if(!epilogue_prevalloc){
// // 仅前面的块未分配才能得知它的地址及大小by NEXT_BLKP()
// prev_bp = PREV_BLKP(heap_hi_bdy);
// prev_size = GET_SIZE(HDRP(prev_bp));
// #ifdef DEBUG
// if(newsize <= prev_size){
// printf(" *** *** malloc错误!旧结尾块前的空闲块(0x%x)的大小能胜任\n",
// PREV_BLKP((char *)mem_heap_hi() + 1));
// }
// #endif // DEBUG
// extend_size = newsize - prev_size;
// #ifdef DEBUG
// if(prev_size%8 != 0){
// printf(" *** *** malloc错误!旧结尾块前的空闲块大小没有八字节对齐\n");
// }
// #endif // DEBUG
// //ALIGN(extend_size);
// if((bp = extend_heap(extend_size/WSIZE)) == NULL){
// #ifdef DEBUG
// printf(" *** *** malloc错误:调用extend_heap失败!\n");
// #endif // DEBUG
// return NULL; //malloc fail
// }
// //进行合并
// bp = Coalesce(bp);
// //借用place的分配能力
// place(bp, newsize);
// #ifdef DEBUG
// printf(" <==== malloc();分配成功,返回值bp: 0x%x size : 0x%x\n\n\n", bp, newsize);
// #endif // DEBUG
// return (void *)bp;
// }
// else
{
extend_size = newsize;
if((bp = extend_heap(extend_size/WSIZE)) == NULL){
#ifdef DEBUG
printf(" *** *** malloc错误:调用extend_heap失败!\n");
#endif // DEBUG
return NULL; //malloc fail
}
place(bp, newsize); //借用place的分配能力
#ifdef DEBUG
printf(" <==== malloc();分配成功,返回值bp: 0x%x size : 0x%x\n\n\n", bp, newsize);
#endif // DEBUG
return (void *)bp;
}
//return (void *)((char *)p + SIZE_T_SIZE); 能够实行不同的系统size_t的大小
}
/* mm_free ----------------------------- begfin ----------------------------- */
/*
* mm_free - Freeing a block does nothing.
* allcated ==> suspended ==> in list
*/
void mm_free(void *ptr)
{
#ifdef DEBUG
printf(" ====> free(0x%x)\n", ptr);
#endif // DEBUG
if(ptr == NULL){
return ;
}
/* 1.物理结构改成未分配, ==>suspended */
PUT(HDRP(ptr), PACK(GET_SIZE(HDRP(ptr)), 0, GET_PREVALLOC(HDRP(ptr)))); //Header
PUT(FTRP(ptr), PACK(GET_SIZE(HDRP(ptr)), 0, GET_PREVALLOC(HDRP(ptr)))); //footer
/* 2.插入逻辑链表, 建立link */
Insert(NULL, ptr);
/* 3.合并一次 */
Coalesce(ptr); //延迟合并,可以改成立即合并
#ifdef DEBUG
printf(" <==== free(0x%x)\n", ptr);
printf("\n\n\n", ptr);
#endif // DEBUG
}
/* mm_free ----------------------------- end ----------------------------- */
/*
* mm_realloc - Implemented simply in terms of mm_malloc and mm_free
*/
void *mm_realloc(void *ptr, size_t size)
{
#ifdef DEBUG
mm_check(__FUNCTION__);
#endif // DEBUG
void *oldptr = ptr;
void *newptr;
size_t copySize, old_size, asize, e_size;// e_size:effective size of the old block
old_size = GET_SIZE(HDRP(ptr));
e_size = old_size - WSIZE;
asize = ALIGN(size + WSIZE);
/* Very Important! because malloc(1)==>realloc(2) */
/* malloc(8)==>realloc(9)
* ml(24) == > ralc(25)
* Note: We don't konw how much part of the bolck is in use. The core of the problem
* is ROUND UP
* Solution: Only the the old_size is smaller than asize, we do nothing,
* or we need to find a new block
*/
/* case 1: ptr is NULL */
if(ptr == NULL)
return mm_malloc(size);
// ptr is not NULL
/* case 2: size is equal to zero */
if(size == 0)
mm_free(ptr);
/* case 3: change the size of the block */
// 3.1 Directly Set in the new place
if(e_size < size ){
// 新块大小大于旧块,有可能太大分配不了
// 0.Out of memory
// 1.新分配一块区域
if((newptr=mm_malloc(size)) == NULL){
return NULL;
}
// 2.将数据复制到新区域
copySize = old_size-WSIZE;
memcpy(newptr, oldptr, copySize);
// 3.释放旧块
mm_free(oldptr);
return newptr;
}
//3.2 Splitted the block if the old size is bigger than old size 16B or more
if(old_size >= asize + MINIBLK_SIZE){
// 分割后剩下的块满足最小的块大小,应该被分离出来
// 1.分割旧块,设置旧块头部+后块PREV_ALLOC(由后块自己完成)
PUT(HDRP(ptr), PACK(asize, 1, GET_PREVALLOC(HDRP(ptr))));
// 2.设置被剩下块的头部和脚部+后块PREV_ALLOC,然后插入free list
PUT(HDRP(NEXT_BLKP(ptr)), PACK(old_size-asize, 0, 1)); //suspended ==> in list
mm_free(NEXT_BLKP(ptr));
return ptr;
}
//3.3 Conservative action:reset the old block
// do nothing
return ptr;
}
/* help function */
/* 设置此块的下一块的PREV_ALLOC位为1或0, 常用*/
static void SET_NEXTBLKP_PREVALLOC(char *bp, size_t val){
char *next_bp = (NEXT_BLKP(bp));
PUT(HDRP(next_bp), PACK(GET_SIZE(HDRP(next_bp)), GET_ALLOC(HDRP(next_bp)), val));
if(GET_SIZE(HDRP(next_bp)) != 0) /* not epilogue padding */
PUT(FTRP(next_bp), PACK(GET_SIZE(HDRP(next_bp)), GET_ALLOC(HDRP(next_bp)), val));
}
02-08
1万+
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)
10-08
1万+
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)