csapp buffer

/*
 * 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 */
    "TheDa",
    /* First member's full name */
    "Wuruohan",
    /* First member's email address */
    "1150562000@qq.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 ALIGN(size) ((((size) + (ALIGNMENT-1)) /(ALIGNMENT))*(ALIGNMENT))
//对齐宏定义

#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))


#define WSIZE     4
//32位处理器中一个字的大小是4B
#define DSIZE     8
//32位处理器中一个双字的大小是8B
/* 每次扩展堆的块大小(系统调用“费时费力”,一次扩展一大块,然后逐渐利用这一大块) */
#define INITCHUNKSIZE (1<<6)
//堆的初始大小
#define CHUNKSIZE (1<<12)
//扩展堆的最小大小
#define LISTMAX     16
//这里的空闲块链表,按照1,2,4,8的大小分类,最大2的32次方大小
#define MAX(x, y) ((x) > (y) ? (x) : (y))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define PACK(size, alloc) ((size) | (alloc))
//size是block大小,alloc是block的分配属性,这两个信息一起设置
#define GET(p)            (*(unsigned int *)(p))
//读取位于p指针位置的一个字
#define PUT(p, val)       (*(unsigned int *)(p) = (val))
//将val的值写入p指针位置
#define SET_PTR(p, ptr) (*(unsigned int *)(p) = (unsigned int)(ptr))
//p指针位置的值变成指针ptr指向的地址
#define GET_SIZE(p)  (GET(p) & ~0x7)
//得知这个block的大小
#define GET_ALLOC(p) (GET(p) & 0x1)
//得知这个block是否被分配了
#define HDRP(ptr) ((char *)(ptr) - WSIZE)
//ptr可以是当前block的首地址,得到当前block的首地址
#define FTRP(ptr) ((char *)(ptr) + GET_SIZE(HDRP(ptr)) - DSIZE)
//ptr可以是当前block的首地址,得到当前block的尾部地址
#define NEXT_BLKP(ptr) ((char *)(ptr) + GET_SIZE((char *)(ptr) - WSIZE))
//ptr可以是当前block的首地址,ptr-4B指向的位置是当前block的头信息,因此得到下一个block的首地址
#define PREV_BLKP(ptr) ((char *)(ptr) - GET_SIZE((char *)(ptr) - DSIZE))
//ptr可以是当前block的首地址,ptr-4B*2指向的位置是上一个block的尾部信息,因此得到上一个block的首地址
#define PRED_PTR(ptr) ((char *)(ptr))
//显示空闲链表祖先指针
#define SUCC_PTR(ptr) ((char *)(ptr) + WSIZE)
//显示空闲链表后继指针,向低地址方向,就是开头空闲链表方向
#define PRED(ptr) (*(char **)(ptr))
//
#define SUCC(ptr) (*(char **)(SUCC_PTR(ptr)))
//
void *segregated_free_lists[LISTMAX];//空闲链表,在这里遍历空闲块
static void *extend_heap(size_t size);//扩展推
static void *coalesce(void *ptr);//合并相邻的Free block
static void *place(void *ptr, size_t size);//在prt所指向的free block块中allocate size大小的块,如果剩下的空间大于2*DWSIZE,则将其分离后放入Free list
static void insert_node(void *ptr, size_t size);//将ptr所指向的free block插入到分离空闲表中
static void delete_node(void *ptr);//将ptr所指向的块从分离空闲表中删除
static void *extend_heap(size_t size)//扩展堆,扩展大小为Size的堆空间,返回堆扩展得到的空闲block的ptr
{
    void *ptr;
    size = ALIGN(size);//首先对齐内存
    if ((ptr = mem_sbrk(size)) == (void *)-1)//系统调用“sbrk”,看看是否能够成功扩大这么大的堆空间
    //如果成功的话返回新的堆上界地址brk(堆是向上生长的,高字节方向)
        return NULL;
    PUT(HDRP(ptr), PACK(size, 0));//设置头部大小是size,属性为空闲
    PUT(FTRP(ptr), PACK(size, 0));//设置尾部大小是size,属性为空闲
    PUT(HDRP(NEXT_BLKP(ptr)), PACK(0, 1));// 注意这个块是堆的结尾,设置一下结尾块 ,头尾信息结构
    insert_node(ptr, size);/* 设置好后将其插入到分离空闲表中 */
    return coalesce(ptr);/* 另外这个free块的前面也可能是一个free块,可能需要合并 */
}
static void insert_node(void *ptr, size_t size)//将ptr指向的大小为size的block插入空闲链表segregated_free_lists当中
{
    int listnumber = 0;
    void *search_ptr = NULL;
    void *insert_ptr = NULL;
    while ((listnumber < LISTMAX - 1) && (size > 1))/* 通过块的大小找到对应的链 */
    {
        size >>= 1;
        listnumber++;
    }
    /* 找到对应的链后,在该链中继续寻找对应的插入位置,以此保持链中块由小到大的特性 */
    search_ptr = segregated_free_lists[listnumber];
    while ((search_ptr != NULL) && (size > GET_SIZE(HDRP(search_ptr))))
    {
        insert_ptr = search_ptr;
        search_ptr = PRED(search_ptr);//insert_ptr的后一个指针是search_ptr
    }
    //最终得到的插入位置是insert_ptr,分情况将该block插入该空闲块链表当中
    if (search_ptr != NULL)//说明插入位置的后一个块不是空,插入位置不是最后一个
    {
        if (insert_ptr != NULL)//在中间插入
        {
            //注意隐式空闲链表和显式空闲链表
            SET_PTR(PRED_PTR(ptr), search_ptr);//插入块高地址方向是search_ptr
            SET_PTR(SUCC_PTR(search_ptr), ptr);//
            SET_PTR(SUCC_PTR(ptr), insert_ptr);//插入块低地址方向是insert_ptr
            SET_PTR(PRED_PTR(insert_ptr), ptr);//
        }
        else//插入位置的后面有block,插入指针为NULL,那么只能是在开头位置插入了
        {
            SET_PTR(PRED_PTR(ptr), search_ptr);
            SET_PTR(SUCC_PTR(search_ptr), ptr);
            SET_PTR(SUCC_PTR(ptr), NULL);
            segregated_free_lists[listnumber] = ptr;//设置该条空闲链首指针
        }
    }
    else
    {
        if (insert_ptr != NULL)//在结尾插入
        {
            SET_PTR(PRED_PTR(ptr), NULL);
            SET_PTR(SUCC_PTR(ptr), insert_ptr);
            SET_PTR(PRED_PTR(insert_ptr), ptr);
        }
        else//该链为空,这是第一次插入
        {
            SET_PTR(PRED_PTR(ptr), NULL);
            SET_PTR(SUCC_PTR(ptr), NULL);
            segregated_free_lists[listnumber] = ptr;
        }
    }
}
static void delete_node(void *ptr)//将ptr指向的block从空闲块链表删除
{
    int listnumber = 0;
    size_t size = GET_SIZE(HDRP(ptr));//得到当前块大小
    while ((listnumber < LISTMAX - 1) && (size > 1))//通过块的大小找到对应的空闲链
    {
        size >>= 1;
        listnumber++;
    }
    if (PRED(ptr) != NULL)//高地址方向,也就是后继块不为空
    {
        if (SUCC(ptr) != NULL)//前向block不为空,中间删除
        {
            SET_PTR(SUCC_PTR(PRED(ptr)), SUCC(ptr));
            SET_PTR(PRED_PTR(SUCC(ptr)), PRED(ptr));
        }
        else//前向block为空,删除空闲块链开头block
        {
            SET_PTR(SUCC_PTR(PRED(ptr)), NULL);
            segregated_free_lists[listnumber] = PRED(ptr);
        }
    }
    else//前向block为空,结尾删除
    {
        if (SUCC(ptr) != NULL)//低地址方向,也就是前向块不为空
        {
            SET_PTR(PRED_PTR(SUCC(ptr)), NULL);
        }
        else//整条空闲链就这一个block
        {
            segregated_free_lists[listnumber] = NULL;
        }
    }
}
static void *coalesce(void *ptr)//尽可能合并ptr指向的block周围的空闲块,mm_free调用,堆扩展调用,返回新block的ptr
{
    _Bool is_prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(ptr)));//低地址方向block分配了吗
    _Bool is_next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(ptr)));//高地址方向block分配了吗
    size_t size = GET_SIZE(HDRP(ptr));//当前block大小
    /* 另外注意到由于我们的合并和申请策略,不可能出现两个相邻的free块 */
    if (is_prev_alloc && is_next_alloc)//前后block均被分配了
    {
        return ptr;
    }
    else if (is_prev_alloc && !is_next_alloc)//只有低地址方向block被分配,高地址方向未分配
    {
        delete_node(ptr);//合并前先删除该空闲块
        delete_node(NEXT_BLKP(ptr));//删除高地址方向空闲块
        size += GET_SIZE(HDRP(NEXT_BLKP(ptr)));//修改size
        PUT(HDRP(ptr), PACK(size, 0));//新block的ptr位置就是ptr
        PUT(FTRP(ptr), PACK(size, 0));//注意size已经改变了,FTRP可以正常使用
    }
    else if (!is_prev_alloc && is_next_alloc)//只有高地址方向block被分配,低地址方向未分配
    {
        delete_node(ptr);//合并前先删除该空闲块
        delete_node(PREV_BLKP(ptr));//删除低地址方向空闲块
        size += GET_SIZE(HDRP(PREV_BLKP(ptr)));//修改size
        PUT(FTRP(ptr), PACK(size, 0));//新block的脚部分位于原ptr的foot
        PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));//新block的头部分位于低地址方向空闲块ptr的头
        ptr = PREV_BLKP(ptr);//ptr变为低地址方向空闲块ptr
    }
    else//前后两个块都是free块,这时将三个块同时合并
    {
        delete_node(ptr);
        delete_node(PREV_BLKP(ptr));
        delete_node(NEXT_BLKP(ptr));
        size += GET_SIZE(HDRP(PREV_BLKP(ptr))) + GET_SIZE(HDRP(NEXT_BLKP(ptr)));
        PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
        PUT(FTRP(NEXT_BLKP(ptr)), PACK(size, 0));
        ptr = PREV_BLKP(ptr);
    }
    insert_node(ptr, size);//将合并好的free块加入到空闲链接表中
    return ptr;
}
//在ptr所指向的空闲块中插入size大小的块,如果剩下的空间大于2*DWSIZE,则将其分离后放入Free list,返回最终块被分配的位置
static void *place(void *ptr, size_t size)
{
    size_t ptr_size = GET_SIZE(HDRP(ptr));
    size_t remainder = ptr_size - size;//在ptr所指向的空闲块中插入size大小的块后剩余的空间大小
    delete_node(ptr);//从空闲链表当中删除ptr
    if (remainder < DSIZE * 2)//如果剩余的大小小于最小块,只需要设置ptr指向block被分配即可
    {
        PUT(HDRP(ptr), PACK(ptr_size, 1));
        PUT(FTRP(ptr), PACK(ptr_size, 1));
    }
    else if (size >= 96)//消除外部碎片的策略,如果插入的是大块,从该空闲块ptr的高地址方向放起
    {
        PUT(HDRP(ptr), PACK(remainder, 0));//注意这一步已经修改了ptr所指向的未分配block的size
        PUT(FTRP(ptr), PACK(remainder, 0));//新的空闲块就生成了
        PUT(HDRP(NEXT_BLKP(ptr)), PACK(size, 1));//由于ptr的size已经修改,下一个分配block就可以这样访问,修改分配block的属性
        PUT(FTRP(NEXT_BLKP(ptr)), PACK(size, 1));
        insert_node(ptr, remainder);//将空闲块插入空闲块链
        return NEXT_BLKP(ptr);
    }
    else//消除外部碎片的策略,如果插入的是小块,从该空闲块ptr的低地址方向放起
    {
        PUT(HDRP(ptr), PACK(size, 1));//ptr指向的位置放分配block
        PUT(FTRP(ptr), PACK(size, 1));
        PUT(HDRP(NEXT_BLKP(ptr)), PACK(remainder, 0));//原理同上
        PUT(FTRP(NEXT_BLKP(ptr)), PACK(remainder, 0));
        insert_node(NEXT_BLKP(ptr), remainder);
    }
    return ptr;
}
int mm_init(void)//初始化堆
{
        int listnumber;
    char *heap;
    for (listnumber = 0; listnumber < LISTMAX; listnumber++)//初始化分离空闲链表
    {
        segregated_free_lists[listnumber] = NULL;
    }
    if ((long)(heap = mem_sbrk(4 * WSIZE)) == -1)//首先开辟一个4*WSIZE大小的空间
        return -1;
    PUT(heap, 0);//堆的头部
    PUT(heap + (1 * WSIZE), PACK(DSIZE, 1));//2*WSIZE的空block
    PUT(heap + (2 * WSIZE), PACK(DSIZE, 1));
    PUT(heap + (3 * WSIZE), PACK(0, 1));//堆的尾部块
    if (extend_heap(INITCHUNKSIZE) == NULL)//扩展堆,得到初始大小的堆
        return -1;
    return 0;
}
void *mm_malloc(size_t size)//自动在堆上分配大小为size的block,并返回分配的block的起始地址
{
        if (size == 0)
        return NULL;
    if (size <= DSIZE)//因为是按照双字对齐,如果大小小于DSiZE,那么分配DSIZE加上2*4B的头尾信息
    {
        size = 2 * DSIZE;
    }
    else
    {
        size = ALIGN(size + DSIZE);//显然大小还要加上头尾信息
    }
    int listnumber = 0;
    size_t searchsize = size;
    void *ptr = NULL;
    while (listnumber < LISTMAX)//首先找到合适的空闲块链表
    {
        if (((searchsize <= 1) && (segregated_free_lists[listnumber] != NULL)))//找到合适的空闲块链了
        {
            ptr = segregated_free_lists[listnumber];
            while ((ptr != NULL) && ((size > GET_SIZE(HDRP(ptr)))))//然后在该空闲块链表上遍历
            {
                ptr = PRED(ptr);
            }
            if (ptr != NULL)//找到了
                break;
        }
        searchsize >>= 1;
        listnumber++;
    }
    if (ptr == NULL)//没有合适大小的block那么我们就需要扩展堆的大小
    {
        if ((ptr = extend_heap(MAX(size, CHUNKSIZE))) == NULL)
            return NULL;
    }
    /* 在free块中allocate size大小的块 */
    ptr = place(ptr, size);
    return ptr;
}
void mm_free(void *ptr)//释放ptr所指向的分配block
{
    size_t size = GET_SIZE(HDRP(ptr));
    PUT(HDRP(ptr), PACK(size, 0));//修改该block的分配属性
    PUT(FTRP(ptr), PACK(size, 0));
    insert_node(ptr, size);
    coalesce(ptr);//先插入,再合并
}
void *mm_realloc(void *ptr, size_t size)//将之前malloc分配的空间修改分配大小,返回重新分配的block的地址
{
    void *new_block = ptr;
    int remainder;
    if (size == 0)
        return NULL;
    if (size <= DSIZE)//内存对齐
    {
        size = 2 * DSIZE;
    }
    else
    {
        size = ALIGN(size + DSIZE);
    }
    if ((remainder = GET_SIZE(HDRP(ptr)) - size) >= 0)//如果size小于原来块的大小,直接返回原来的块
    {
        return ptr;
    }
    //现在势必要借用虚拟内存了,size有点大
    
   
    else if(  (!GET_ALLOC(HDRP(NEXT_BLKP(ptr))))   &&  GET_SIZE(HDRP(NEXT_BLKP(ptr)))>0  )//如果后面的一个block是空闲块
    {
        if((remainder = GET_SIZE(HDRP(ptr)) + GET_SIZE(HDRP(NEXT_BLKP(ptr))) - size)>=0)//如果加上后面的空闲块可以完成
        {
            delete_node(NEXT_BLKP(ptr));
            PUT(HDRP(ptr), PACK(size , 1));
            PUT(FTRP(ptr), PACK(size , 1));
            PUT(HDRP(NEXT_BLKP(ptr)), PACK(remainder, 0));
            PUT(FTRP(NEXT_BLKP(ptr)), PACK(remainder, 0));
            insert_node(NEXT_BLKP(ptr), remainder);
        }
        else//如果加上后面的空闲块不能完成,空闲块后面可能是利用块,也可能是结尾,是结尾的情况直接扩展堆会包含,因为扩展堆会合并空闲块
        {
            if(  !GET_SIZE(HDRP(NEXT_BLKP(NEXT_BLKP(ptr))))   )//如果后面一个空闲块的后面还是结尾
            {
                remainder=size-GET_SIZE(HDRP(ptr))-GET_SIZE(HDRP(NEXT_BLKP(ptr)));//还差多少
                if (extend_heap(MAX(remainder, CHUNKSIZE)) == NULL)
                        return NULL;
                delete_node(NEXT_BLKP(ptr));//后面一个是彻底被吸收了
                remainder=MAX(remainder, CHUNKSIZE);
                PUT(HDRP(ptr), PACK(GET_SIZE(HDRP(ptr)) + GET_SIZE(HDRP(NEXT_BLKP(ptr))) + remainder, 1));
                PUT(FTRP(ptr), PACK(GET_SIZE(HDRP(ptr)) + GET_SIZE(HDRP(NEXT_BLKP(ptr))) + remainder, 1));
            }
            else//那么就不能利用后面的空闲块了
            {
                new_block = mm_malloc(size);
                memcpy(new_block, ptr, GET_SIZE(HDRP(ptr)));
                mm_free(ptr);
            }
        }
    }
    else if(!GET_SIZE(HDRP(NEXT_BLKP(ptr))) )//如果后一个block就是空,当前是结尾
    {
        remainder=size-GET_SIZE(HDRP(ptr));//还差多少
        if (extend_heap(MAX(remainder, CHUNKSIZE)) == NULL)
                return NULL;
        remainder=MAX(remainder, CHUNKSIZE);
        PUT(HDRP(ptr), PACK(GET_SIZE(HDRP(ptr)) + remainder, 1));
        PUT(FTRP(ptr), PACK(GET_SIZE(HDRP(ptr))+ remainder, 1));
    }
    
    /*
    else if (!GET_ALLOC(HDRP(NEXT_BLKP(ptr))) || !GET_SIZE(HDRP(NEXT_BLKP(ptr))))//如果高地址方向的下一块没有被分配,或者没有下一块了,这个块已经结束了
    {
        if ((remainder = GET_SIZE(HDRP(ptr)) + GET_SIZE(HDRP(NEXT_BLKP(ptr))) - size) < 0)
        {
            if (extend_heap(MAX(-remainder, CHUNKSIZE)) == NULL)
                return NULL;
            remainder += MAX(-remainder, CHUNKSIZE);
        }
        delete_node(NEXT_BLKP(ptr));
        PUT(HDRP(ptr), PACK(size + remainder, 1));
        PUT(FTRP(ptr), PACK(size + remainder, 1));
    }
    //没有可以利用的连续free块,而且size大于原来的块,这时只能申请新的不连续的free块、复制原块内容、释放原块
    */
    else//直接选择malloc一个新的出来
    {
        new_block = mm_malloc(size);
        memcpy(new_block, ptr, GET_SIZE(HDRP(ptr)));
        mm_free(ptr);
    }
    return new_block;
}














posted @ 2021-11-08 00:02  TheDa  阅读(44)  评论(0编辑  收藏  举报