建议先学会书本的隐式空闲链表, 再学此显式空闲链表
显式空闲链表(双向空闲链表)的堆块格式
使用显式空闲链表使得首次适配的分配时间从块总数(n)的线性时间减少到了空闲块数量(m)的线性时间:O(m) < O(n),其中m < n。释放块和合并块与隐式空闲链表一样都是O(1)。
显示空闲链表的格式
宏marco
#define WSIZE 4
#define DSIZE 8
#define CHUNKSIZE (1 << 12)
#define MAX(x, y) ((x) > (y) ? (x) : (y))
/* Pack a size and allocated bit into a 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)))
#define NEXT_NODEPTR(bp) ((char *)(bp) + WSIZE)
#define PREV_NODEPTR(bp) ((char *)(bp))
只有最后两句是新增的(其余与书本一致),PREV_NODEPTR(bp)表示PREV指针,NEXT_NODEPTR(bp)表示NEXT指针
函数原型
4个基本操作函数:
int mm_init(void); // 创建带一个初始空闲块的堆
void *mm_malloc(size_t size);
void mm_free(void *ptr);
void *mm_realloc(void *ptr, size_t size);
其他函数:
static void *extend_heap(size_t words); // 用一个新的空闲块扩展堆
static void *coalesce(void *bp); // 合并
static void *find_fit(size_t asize); // 首次适配
static void place(void *bp, size_t asize); // 放置
void make_lifo(char *ptr); // LIFO(新free的块放表头)
void fix_ptr(char *ptr); // 调整prev、next指针
两个全局变量:
static char *heap_listp = NULL;
static char *root = NULL;
函数详解
首先是mm_init():
int mm_init(void)
{
/* Creat the initial empty heap */
if ((heap_listp = mem_sbrk(6 * WSIZE)) == (void *)-1)
return -1;
PUT(heap_listp, 0);
PUT(heap_listp + (1 * WSIZE), 0); // Prev_nodeptr
PUT(heap_listp + (2 * WSIZE), 0); // Next_nodeptr
PUT(heap_listp + (3 * WSIZE), PACK(DSIZE, 1));
PUT(heap_listp + (4 * WSIZE), PACK(DSIZE, 1));
PUT(heap_listp + (5 * WSIZE), PACK