本文为USTC SSE CSAPP 2020 Fall实验三的记录,仅供参考
PPT链接在这里:Lab 5.pptx 代码在这里 mm2.c mm3.c
版本一代码如下(无注释 注释请看版本二):
/*
* 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 "memlib.h"
#include "stdio.h"
#include "string.h"
#include <stdlib.h>
#include <assert.h>
#include <unistd.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 */
"123456",
/* First member's full name */
"xxx xxx",
/* First member's email address */
"xxxx@mail.ustc.edu.cn",
/* 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
// 注释请参照 mm3.c
/* rounds up to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & (~(ALIGNMENT-1)))
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
#define base_type size_t
#define base_pt base_type*
#define BASE_TYPE(e) ((base_type)e)
#define BASE_PT(e) ((base_pt)e)
#define BASE_TYPE_SIZE (ALIGN(sizeof(base_type)))
#define INITED ~0
#define OVHD_PREV_IDX -3
#define OVHD_NEXT_IDX -2
#define OVHD_SIZE_IDX -1
#define HD_INIT_IDX 0
#define FB_LIST_NUM 9
#define HD_N (FB_LIST_NUM + 1)
#define OVHD_N 3
#define HD_SIZE (BASE_TYPE_SIZE * HD_N)
#define OVHD_SIZE (BASE_TYPE_SIZE * OVHD_N)
#define TAIL_SIZE BASE_TYPE_SIZE
#define OV_SIZE (ALIGN(OVHD_SIZE + TAIL_SIZE))
#define inc_n_byte(p, n) ((base_pt)((((char*)(p)) + n)))
#define HEAP_START_PT (inc_n_byte(mem_heap_lo(), HD_SIZE))
#define calc_blcok_total_size(alloc_size) (OVHD_SIZE + ALIGN(alloc_size) + TAIL_SIZE)
#define BLOCK_USED 0
#define BLOCK_FREE 1
#define BLOCK_FLAG_BITS 1
#define BLOCK_FLAG_MASK ((1 << BLOCK_FLAG_BITS) - 1)
#define calc_size_val(size, v) ((size << BLOCK_FLAG_BITS) | v)
#define m_read(p, idx) (((base_pt)(p))[((base_type)(idx))])
#define m_write(p, idx, v) (m_read(p, idx) = ((base_type)v))
#define hd_read(idx) (m_read(mem_heap_lo(), idx))
#define hd_write(idx, v) (m_write(mem_heap_lo(), idx, v))
#define hd_inited (m_read(mem_heap_lo(), HD_INIT_IDX))
#define set_hd_inited() (m_write(mem_heap_lo(), HD_INIT_IDX, INITED))
#define block_flag(p) ((m_read(p, OVHD_SIZE_IDX)) & BLOCK_FLAG_MASK)
#define block_size(p) ((m_read(p, OVHD_SIZE_IDX)) >> BLOCK_FLAG_BITS)
#define block_last(p) (inc_n_byte(p, ((block_size(p)) - (OV_SIZE))))
#define block_next(p) (BASE_PT(m_read(p, OVHD_NEXT_IDX)))
#define block_prev(p) (BASE_PT(m_read(p, OVHD_PREV_IDX)))
#define block_content_pt(p) (inc_n_byte(p, OVHD_SIZE))
#define is_block_used(p) ((block_flag(p)) == (BLOCK_USED))
#define is_block_free(p) ((block_flag(p)) != (BLOCK_USED))
#define set_block_hd_size(p, v) (m_write(p, OVHD_SIZE_IDX, v))
#define set_block_td_size(p, v) (m_write(block_last(p), 0, v))
#define set_block_next(p, v) (m_write(p, OVHD_NEXT_IDX, v))
#define set_block_prev(p, v) (m_write(p, OVHD_PREV_IDX, v))
#define REMIAN_SIZE (ALIGN(sizeof(base_type) * 3))
#define EXTRA_SAPCE (ALIGN(REMIAN_SIZE + OV_SIZE))
#define print(m_type) (printf("sizeof(" #m_type "): %d\n", sizeof(m_type)))
#define DEBUG_MODE 0
void set_block_size(base_pt block, base_type total_size, base_type block_flag) {
base_type size_val = calc_size_val(total_size, block_flag);
set_block_hd_size(block, size_val);
set_block_td_size(block, size_val);
}
#define set_block_used(block, total_size) (set_block_size(block, total_size, BLOCK_USED))
#define set_block_free(block, total_size) (set_block_size(block, total_size, BLOCK_FREE))
#define mark_block_used(block) (set_block_used(block, block_size(block)))
#define mark_block_free(block) (set_block_free(block, block_size(block)))
void px(void* p, int x) {
for (int i = 0; i < x; i++) {
printf("i:%d, addr: 0x%x, content:0x%x\n", i, &m_read(p, i), m_read(p, i));
}
}
void print_type_info() {
printf("\n");
print(char*);
print(void*);
print(base_pt);
print(base_type);
print(int);
printf("\n");
}
base_type get_list_idx(base_type total_size) {
base_type idx[FB_LIST_NUM - 1] = {48, 64, 128, 256, 512, 1024, 2072, 4104};
base_type i = 0;
for (; i < FB_LIST_NUM - 1; i++)
if (total_size <= idx[i])
break;
return i + 1;
}
void insert_into_free_list_head(base_pt block) {
base_type size = block_size(block);
base_type list_idx = get_list_idx(size);
// if (DEBUG_MODE)
// printf("insert block(addr:%p size:%d) into list %d\n", block, size, list_idx);
set_block_free(block, size);
set_block_prev(block, NULL);
set_block_next(block, NULL);
base_pt head = BASE_PT(hd_read(list_idx));
if (head == NULL) {
hd_write(list_idx, block);
}
else {
base_pt old_head = head;
hd_write(list_idx, block);
set_block_next(block, old_head);
if (old_head)
set_block_prev(old_head, block);
}
}
void print_list() {
// printf("\n");
for (base_type i = 1; i <= FB_LIST_NUM; i++) {
printf("list: idx=%d, element:", i);
base_pt pt = hd_read(i);
while(pt != NULL) {
printf("[%p(%d:%d)]", pt, block_size(pt), block_flag(pt));
pt = block_next(pt);
if (pt)
printf(" -> ");
}
printf("\n");
}
printf("\n");
}
base_pt search_free_list(base_type total_size) {
base_type list_idx = get_list_idx(total_size);
for (base_type idx = list_idx; idx <= FB_LIST_NUM; idx++) {
base_pt pt = BASE_PT(hd_read(idx));
while (pt && (block_size(pt) < total_size))
pt = block_next(pt);
if (pt) {
if (DEBUG_MODE)
printf("found free block(addr:%p, size:%d)\n", pt, block_size(pt));
return pt;
}
}
if (DEBUG_MODE)
printf("found no free block\n");
return NULL;
}
void remove_from_free_list(base_pt block) {
base_type list_idx = get_list_idx(block_size(block));
if (!block_prev(block))
hd_write(list_idx, block_next(block));
else
set_block_next(block_prev(block), block_next(block));
if (block_next(block))
set_block_prev(block_next(block), block_prev(block));
set_block_prev(block, NULL);
set_block_next(block, NULL);
mark_block_used(block);
return block;
}
base_pt split_block(base_pt block, base_type total_size) {
base_type size = block_size(block);
if (is_block_used(block)) {
printf("split block error: try to split an used block\n");
return NULL;
}
if (size < total_size) {
printf("split block error: try to split block into bigger blocks.\n");
return NULL;
}
else {
remove_from_free_list(block);
if (size >= (total_size + EXTRA_SAPCE)) {
base_pt new_block = inc_n_byte(block, total_size);
base_pt list_idx = get_list_idx(size);
set_block_used(block, total_size);
set_block_used(new_block, size - total_size);
if (DEBUG_MODE)
printf("split free block(addr:%p, size:%d) into ret block(addr:%p, size:%d) and ", block, size, block, block_size(block));
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", new_block, block_size(new_block));
insert_into_free_list_head(new_block);
}
return block;
}
}
void* true_malloc(base_type total_size) {
base_pt *p = BASE_PT(mem_sbrk(total_size));
// printf("info: true malloc has got a new block with addr: %p, size: %llu\n", p, total_size);
if (p == -1)
return NULL;
p = block_content_pt(p);
set_block_next(p, NULL);
set_block_prev(p, NULL);
set_block_used(p, total_size);
return (void*)p;
}
int mm_init (void) {
// print_type_info();
base_type r = BASE_TYPE(mem_sbrk(HD_SIZE));
if (r == -1)
return -1;
set_hd_inited();
for (base_type i = 1; i <= FB_LIST_NUM; i++)
hd_write(i, NULL);
// printf("low: 0x%x, high:0x%x\n", mem_heap_lo(), mem_heap_hi());
// px(mem_heap_lo(), 5);
return 0;
}
void * mm_malloc (size_t size) {
if (!size) return NULL;
if (hd_inited != INITED) {
printf("error: try to call malloc before inited.\n");
return NULL;
}
base_type total_size = calc_blcok_total_size(size);
base_pt pt = search_free_list(total_size);
if (pt == NULL) {
void *r = true_malloc(total_size);
if (DEBUG_MODE) {
printf("malloc: request size: %d, allocated addr: %p, size: %d\n", size, r, block_size(r));
print_list();
}
return r;
}
else {
void *r = split_block(pt, total_size);
if (DEBUG_MODE) {
printf("malloc: request size: %d, allocated addr: %p, size: %d\n", size, r, block_size(r));
print_list();
}
return r;
}
}
void mm_free(void *ptr) {
if (hd_inited != INITED) {
printf("free rror: try to call free before inited.\n");
return;
}
base_pt pt = BASE_PT(ptr);
if (is_block_free(pt)) {
printf("free error: try to free a free block with addr: %p\n", pt);
return;
}
if (DEBUG_MODE)
printf("free: try to free a block with addr:%p, size:%d\n", ptr, block_size(ptr));
base_type size = block_size(pt);
if (DEBUG_MODE)
printf("-----------------free analysis for block(addr:%p, size:%d)------------------------\n", pt, size);
base_type prev_block_size_val_pt = inc_n_byte(pt, -(OVHD_SIZE + BASE_TYPE_SIZE));
if (DEBUG_MODE)
printf("prev: size_val_pt:%p heap_start:%p\n", prev_block_size_val_pt, HEAP_START_PT);
if (prev_block_size_val_pt > HEAP_START_PT) {
base_type prev_block_size_val = m_read(pt, -(OVHD_N + 1));
if (DEBUG_MODE)
printf("prev_block_size_val:0x%x, flag:%x\n", prev_block_size_val, prev_block_size_val & BLOCK_FLAG_MASK);
if ((prev_block_size_val & BLOCK_FLAG_MASK) != BLOCK_USED) {
base_type prev_block_size = (prev_block_size_val >> BLOCK_FLAG_BITS);
base_pt prev_block = inc_n_byte(pt, -prev_block_size);
if (DEBUG_MODE)
printf("merge current block(addr:%p size:%d) and prev block(addr:%p size:%d) into ", pt, size, prev_block, prev_block_size);
remove_from_free_list(prev_block);
size += prev_block_size;
pt = prev_block;
set_block_size(pt, size, BLOCK_USED);
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", pt, block_size(pt));
}
}
base_pt next_block = inc_n_byte(pt, size);
if (DEBUG_MODE)
printf("next: block_pt:%p heap_hi:%p\n", next_block, mem_heap_hi());
if (next_block < mem_heap_hi()) {
base_type next_block_size_val = m_read(next_block, OVHD_SIZE_IDX);
if (DEBUG_MODE)
printf("next_block_size_val:0x%x flag:%x\n", next_block_size_val, next_block_size_val & BLOCK_FLAG_MASK);
if ((next_block_size_val & BLOCK_FLAG_MASK) != BLOCK_USED) {
base_type next_block_size = (next_block_size_val >> BLOCK_FLAG_BITS);
if (DEBUG_MODE)
printf("merge current block(addr:%p size:%d) and next block(addr:%p size:%d) into", pt, size, next_block, next_block_size);
remove_from_free_list(next_block);
set_block_size(pt, size + next_block_size, BLOCK_USED);
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", pt, block_size(pt));
}
}
if (DEBUG_MODE)
printf("----------------------------------free analysis end--------------------------------------\n", pt, size);
insert_into_free_list_head(pt);
if (DEBUG_MODE)
print_list();
}
void *mm_realloc(void *ptr, size_t size) {
if (hd_inited != INITED) {
printf("error: try to call realloc before inited.\n");
return NULL;
}
if (DEBUG_MODE)
printf("realloc: try to realloc a block with addr:%p, size:%d\n", ptr, size);
if (!ptr) return mm_malloc(size);
if (!size) {
mm_free(ptr);
return NULL;
}
base_type blockSize = block_size(ptr);
base_type adjusted_size = calc_blcok_total_size(size);
if (adjusted_size <= blockSize) {
if (DEBUG_MODE)
print_list();
return ptr;
}
else {
base_pt new_ptr = mm_malloc(size);
if (!new_ptr) return NULL;
memcpy(new_ptr, ptr, blockSize - OVHD_SIZE);
mm_free(ptr);
if (DEBUG_MODE)
print_list();
return new_ptr;
}
}
版本二代码如下:
/*
* 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 "memlib.h"
#include "stdio.h"
#include "string.h"
#include <stdlib.h>
#include <assert.h>
#include <unistd.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 */
"123456",
/* First member's full name */
"xxx xxx",
/* First member's email address */
"xxxx@mail.ustc.edu.cn",
/* 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)) & (~(ALIGNMENT-1)))
// 一些常用的type和他们的size
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
#define base_type size_t
#define base_pt base_type*
#define BASE_TYPE(e) ((base_type)e)
#define BASE_PT(e) ((base_pt)e)
#define BASE_TYPE_SIZE (ALIGN(sizeof(base_type)))
// 堆头部初始化标志
#define INITED ~0
// 块头部的值的下标 相对块的内容的第一个字节的指针
#define OVHD_PREV_IDX -3
#define OVHD_NEXT_IDX -2
#define OVHD_SIZE_IDX -1
// 堆头部得下标
#define HD_INIT_IDX 0
#define FB_LIST_NUM 9
// 堆头部的值的个数v
#define HD_N (FB_LIST_NUM + 1)
// 块头部的值的个数 OV为Overhead
#define OVHD_N 3
// 堆头部的大小
#define HD_SIZE (BASE_TYPE_SIZE * HD_N)
// 块头部的大小
#define OVHD_SIZE (BASE_TYPE_SIZE * OVHD_N)
// 块尾部的大小
#define TAIL_SIZE BASE_TYPE_SIZE
// 一个块头部加尾部的大小
#define OV_SIZE (ALIGN(OVHD_SIZE + TAIL_SIZE))
// 将一个指针前进n个字节,n为负数则为后退
#define inc_n_byte(p, n) ((base_pt)((((char*)(p)) + n)))
// 堆上非堆头部的最小的地址
#define HEAP_START_PT (inc_n_byte(mem_heap_lo(), HD_SIZE))
// 给定块内容的大小,计算整个块最小的size
#define calc_blcok_total_size(alloc_size) (OVHD_SIZE + ALIGN(alloc_size) + TAIL_SIZE)
// 用于块的标志位 0为已分配 1为空闲块
#define BLOCK_USED 0
#define BLOCK_FREE 1
#define BLOCK_FLAG_BITS 1
#define BLOCK_FLAG_MASK ((1 << BLOCK_FLAG_BITS) - 1)
// 用size和flag构造出存储在块size部分的值
#define calc_size_val(size, flag) ((size << BLOCK_FLAG_BITS) | flag)
// 将指针p看成base_pt类型 读取p[idx] 和 写入 p[idx] = v
#define m_read(p, idx) (((base_pt)(p))[((base_type)(idx))])
#define m_write(p, idx, v) (m_read(p, idx) = ((base_type)v))
// 读写堆头部的数据结构
#define hd_read(idx) (m_read(mem_heap_lo(), idx))
#define hd_write(idx, v) (m_write(mem_heap_lo(), idx, v))
// 读取堆头部是否初始化的信息
#define hd_inited (m_read(mem_heap_lo(), HD_INIT_IDX))
// 设置堆头部已经初始化
#define set_hd_inited() (m_write(mem_heap_lo(), HD_INIT_IDX, INITED))
// p为看成指向一个块的内容部分的第一个字节的指针,读取这个块的标志位,大小,next指针,prev指针,整个块的最后一个字节
#define block_flag(p) ((m_read(p, OVHD_SIZE_IDX)) & BLOCK_FLAG_MASK)
#define block_size(p) ((m_read(p, OVHD_SIZE_IDX)) >> BLOCK_FLAG_BITS)
#define block_next(p) (BASE_PT(m_read(p, OVHD_NEXT_IDX)))
#define block_prev(p) (BASE_PT(m_read(p, OVHD_PREV_IDX)))
#define block_last(p) (inc_n_byte(p, ((block_size(p)) - (OV_SIZE))))
// p为指向一个块的第一个字节的指针,计算得到指向这个块的内容部分的第一个字节的指针
#define block_content_pt(p) (inc_n_byte(p, OVHD_SIZE))
// v为块的size1部分的内容,看是否为空闲块
#define is_free(v) (((v) & BLOCK_FLAG_BITS) != BLOCK_USED)
// p为看成指向一个块的内容部分的第一个字节的指针,看这个块是空闲块还是已分配块
#define is_block_used(p) ((block_flag(p)) == (BLOCK_USED))
#define is_block_free(p) ((block_flag(p)) != (BLOCK_USED))
// p为看成指向一个块的内容部分的第一个字节的指针,设置头部的size部分,尾部的size部分,next指针,prev指针
#define set_block_hd_size(p, v) (m_write(p, OVHD_SIZE_IDX, v))
#define set_block_td_size(p, v) (m_write(block_last(p), 0, v))
#define set_block_next(p, v) (m_write(p, OVHD_NEXT_IDX, v))
#define set_block_prev(p, v) (m_write(p, OVHD_PREV_IDX, v))
// 用于在分裂空闲块时,如剩下部分小于这个值,就不再拆开块
#define REMIAN_SIZE (ALIGN(sizeof(base_type) * 3))
#define EXTRA_SAPCE (ALIGN(REMIAN_SIZE + OV_SIZE))
// 用于调试 打印各种type的大小
#define print(m_type) (printf("sizeof(" #m_type "): %d\n", sizeof(m_type)))
// 是否是调试模式
#define DEBUG_MODE 0
// 给定一个指向一个块的内容部分的第一个字节的指针,设置其size部分的值,包括头部和尾部
void set_block_size(base_pt block, base_type total_size, base_type block_flag) {
base_type size_val = calc_size_val(total_size, block_flag);
set_block_hd_size(block, size_val);
set_block_td_size(block, size_val);
}
// 同上,只是不用再填 block_flag
#define set_block_used(block, total_size) (set_block_size(block, total_size, BLOCK_USED))
#define set_block_free(block, total_size) (set_block_size(block, total_size, BLOCK_FREE))
// 功能同上 只修改flag 不改变块大小
#define mark_block_used(block) (set_block_used(block, block_size(block)))
#define mark_block_free(block) (set_block_free(block, block_size(block)))
void px(void* p, int x) {
for (int i = 0; i < x; i++) {
printf("i:%d, addr: 0x%x, content:0x%x\n", i, &m_read(p, i), m_read(p, i));
}
}
void print_type_info() {
printf("\n");
print(char*);
print(void*);
print(base_pt);
print(base_type);
print(int);
printf("\n");
}
// 给定整个块的大小,返回其应该在的链表头指针在堆头部的下标
base_type get_list_idx(base_type total_size) {
base_type idx[FB_LIST_NUM - 1] = {48, 64, 128, 256, 512, 1024, 2072, 4104};
base_type i = 0;
for (; i < FB_LIST_NUM - 1; i++)
if (total_size <= idx[i])
break;
return i + 1;
}
// 将一个块插入空闲链表的头部
void insert_into_free_list_head(base_pt block) {
base_type size = block_size(block);
base_type list_idx = get_list_idx(size);
// if (DEBUG_MODE)
// printf("insert block(addr:%p size:%d) into list %d\n", block, size, list_idx);
set_block_free(block, size);
set_block_prev(block, NULL);
set_block_next(block, NULL);
base_pt head = BASE_PT(hd_read(list_idx));
if (head == NULL) {
hd_write(list_idx, block);
}
else {
base_pt old_head = head;
hd_write(list_idx, block);
set_block_next(block, old_head);
if (old_head)
set_block_prev(old_head, block);
}
}
// 调试用的函数 用于打印出所有的空闲链表
void print_list() {
// printf("\n");
for (base_type i = 1; i <= FB_LIST_NUM; i++) {
printf("list: idx=%d, element:", i);
base_pt pt = hd_read(i);
while(pt != NULL) {
printf("[%p(%d:%d)]", pt, block_size(pt), block_flag(pt));
pt = block_next(pt);
if (pt)
printf(" -> ");
}
printf("\n");
}
printf("\n");
}
// 在所有空闲链表中查找>=total_size的空闲块,返回块指针
base_pt search_free_list(base_type total_size) {
base_type list_idx = get_list_idx(total_size);
// 先计算出起始要找的链表的下标,这个链表如果没找到,就再到下一个链表继续找
for (base_type idx = list_idx; idx <= FB_LIST_NUM; idx++) {
base_pt pt = BASE_PT(hd_read(idx));
while (pt && (block_size(pt) < total_size))
pt = block_next(pt);
if (pt) {
if (DEBUG_MODE)
printf("found free block(addr:%p, size:%d)\n", pt, block_size(pt));
return pt;
}
}
if (DEBUG_MODE)
printf("found no free block\n");
return NULL;
}
// 将一个块从空闲链表中移除
void remove_from_free_list(base_pt block) {
base_type list_idx = get_list_idx(block_size(block));
if (!block_prev(block))
hd_write(list_idx, block_next(block));
else
set_block_next(block_prev(block), block_next(block));
if (block_next(block))
set_block_prev(block_next(block), block_prev(block));
set_block_prev(block, NULL);
set_block_next(block, NULL);
mark_block_used(block);
return block;
}
// 空闲块太大,将一个空闲块进行分裂
base_pt split_block(base_pt block, base_type total_size) {
base_type size = block_size(block);
if (is_block_used(block)) {
printf("split block error: try to split an used block\n");
return NULL;
}
if (size < total_size) {
printf("split block error: try to split block into bigger blocks.\n");
return NULL;
}
else {
remove_from_free_list(block);
// 剩下部分比较多,就把剩下部分变成一个新的空闲块插入链表
// 剩下部分不多就把整个块都分配出去
if (size >= (total_size + EXTRA_SAPCE)) {
base_pt new_block = inc_n_byte(block, total_size);
set_block_used(block, total_size);
set_block_used(new_block, size - total_size);
if (DEBUG_MODE)
printf("split free block(addr:%p, size:%d) into ret block(addr:%p, size:%d) and ", block, size, block, block_size(block));
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", new_block, block_size(new_block));
insert_into_free_list_head(new_block);
}
return block;
}
}
// 真正向系统要求分配一个大小为total_size的块
void* true_malloc(base_type total_size) {
base_pt *p = BASE_PT(mem_sbrk(total_size));
// printf("info: true malloc has got a new block with addr: %p, size: %llu\n", p, total_size);
if (p == -1)
return NULL;
p = block_content_pt(p);
set_block_next(p, NULL);
set_block_prev(p, NULL);
set_block_used(p, total_size);
return (void*)p;
}
// 将一个块与其前后的空闲块进行合并
base_pt merge_prev_next_block(base_pt ptr) {
base_pt pt = BASE_PT(ptr);
base_type size = block_size(pt);
if (DEBUG_MODE)
printf("-----------------free analysis for block(addr:%p, size:%d)------------------------\n", pt, size);
// 指向前一个块的尾部的size部分的指针
base_type prev_block_size_val_pt = inc_n_byte(pt, -(OVHD_SIZE + BASE_TYPE_SIZE));
if (DEBUG_MODE)
printf("prev: size_val_pt:%p heap_start:%p\n", prev_block_size_val_pt, HEAP_START_PT);
// 指向前一个块的尾部的size部分的指针 不能小于 堆真正开始处的地址
if (prev_block_size_val_pt > HEAP_START_PT) {
// 解析处前一个块的size部分的值 由size和flag构成
base_type prev_block_size_val = m_read(pt, -(OVHD_N + 1));
if (DEBUG_MODE)
printf("prev_block_size_val:0x%x, flag:%x\n", prev_block_size_val, prev_block_size_val & BLOCK_FLAG_MASK);
// 如果前一个块为空闲块
if (is_free(prev_block_size_val)) {
base_type prev_block_size = (prev_block_size_val >> BLOCK_FLAG_BITS);
base_pt prev_block = inc_n_byte(pt, -prev_block_size);
if (DEBUG_MODE)
printf("merge current block(addr:%p size:%d) and prev block(addr:%p size:%d) into ", pt, size, prev_block, prev_block_size);
remove_from_free_list(prev_block);
size += prev_block_size;
pt = prev_block;
set_block_size(pt, size, BLOCK_USED);
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", pt, block_size(pt));
}
}
// 指向下一个块的内容部分的第一个字节的指针
base_pt next_block = inc_n_byte(pt, size);
if (DEBUG_MODE)
printf("next: block_pt:%p heap_hi:%p\n", next_block, mem_heap_hi());
// 指向下一个块的内容部分的第一个字节的指针 不能超出堆的最大范围
if (next_block < mem_heap_hi()) {
// 找出下一个块的size部分的值 包括size和flag
base_type next_block_size_val = m_read(next_block, OVHD_SIZE_IDX);
if (DEBUG_MODE)
printf("next_block_size_val:0x%x flag:%x\n", next_block_size_val, next_block_size_val & BLOCK_FLAG_MASK);
// 如果为空闲块
if (is_free(next_block_size_val)) {
// 下一个块的大小
base_type next_block_size = (next_block_size_val >> BLOCK_FLAG_BITS);
if (DEBUG_MODE)
printf("merge current block(addr:%p size:%d) and next block(addr:%p size:%d) into", pt, size, next_block, next_block_size);
remove_from_free_list(next_block);
set_block_size(pt, size + next_block_size, BLOCK_USED);
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", pt, block_size(pt));
}
}
if (DEBUG_MODE)
printf("----------------------------------free analysis end---------------------------------------------\n");
return pt;
}
int mm_init (void) {
// print_type_info();
base_type r = BASE_TYPE(mem_sbrk(HD_SIZE));
if (r == -1)
return -1;
set_hd_inited();
// 将各个链表的指针设置为NULL
for (base_type i = 1; i <= FB_LIST_NUM; i++)
hd_write(i, NULL);
// printf("low: 0x%x, high:0x%x\n", mem_heap_lo(), mem_heap_hi());
// px(mem_heap_lo(), 5);
return 0;
}
void * mm_malloc (size_t size) {
if (!size) return NULL;
if (hd_inited != INITED) {
printf("error: try to call malloc before inited.\n");
return NULL;
}
base_type total_size = calc_blcok_total_size(size);
base_pt pt = search_free_list(total_size);
if (pt == NULL) {
// 请参考merge_prev_next_block
base_type alloc_size = total_size;
base_pt prev_block_size_pt = inc_n_byte(mem_heap_hi(), -(BASE_TYPE_SIZE - 1));
if (DEBUG_MODE) {
base_type size_val = *prev_block_size_pt;
printf("prev_block_size_pt:%p heap_start:%p, size:%d, flag:%d\n", prev_block_size_pt,
HEAP_START_PT, size_val >> BLOCK_FLAG_BITS, size_val & BLOCK_FLAG_MASK);
}
if (prev_block_size_pt > HEAP_START_PT & is_free((*prev_block_size_pt))) {
// 在没有适合的空闲块时,要分配一个,如前面一个块为空闲块,则可以减少分配量
base_type prev_block_size = ((*prev_block_size_pt) >> BLOCK_FLAG_BITS);
base_pt new_block = true_malloc(total_size - prev_block_size + OV_SIZE);
if (DEBUG_MODE) {
printf("malloc: prev block(addr:%p size:%d flag:%d)\n", 0, prev_block_size, ((*prev_block_size_pt) & BLOCK_FLAG_MASK));
printf("true malloc: block(addr:%p size:%d flag:%d)\n", new_block, block_size(new_block), block_flag(new_block));
}
base_pt merged_pt = merge_prev_next_block(new_block);
if (DEBUG_MODE) {
printf("malloc: request size: %d, allocated addr: %p, size: %d\n", size, merged_pt, block_size(merged_pt));
print_list();
}
return merged_pt;
}
// 直接向系统申请分配
void *r = true_malloc(total_size);
if (DEBUG_MODE) {
printf("malloc: request size: %d, allocated addr: %p, size: %d\n", size, r, block_size(r));
print_list();
}
return r;
}
else {
// 存在所需的空闲块,对其进行分裂
void *r = split_block(pt, total_size);
if (DEBUG_MODE) {
printf("malloc: request size: %d, allocated addr: %p, size: %d\n", size, r, block_size(r));
print_list();
}
return r;
}
}
void mm_free(void *ptr) {
if (hd_inited != INITED) {
printf("free rror: try to call free before inited.\n");
return;
}
if (is_block_free(ptr)) {
printf("free error: try to free a free block with addr: %p\n", ptr);
return;
}
if (DEBUG_MODE)
printf("free: try to free a block with addr:%p, size:%d\n", ptr, block_size(ptr));
// 先合并前后的空闲块,再插入空闲块链表
base_pt pt = merge_prev_next_block(ptr);
insert_into_free_list_head(pt);
if (DEBUG_MODE)
print_list();
}
void *mm_realloc(void *ptr, size_t size) {
if (hd_inited != INITED) {
printf("error: try to call realloc before inited.\n");
return NULL;
}
if (DEBUG_MODE)
printf("realloc: try to realloc a block with addr:%p, size:%d\n", ptr, size);
if (!ptr) return mm_malloc(size);
if (!size) {
mm_free(ptr);
return NULL;
}
base_type blockSize = block_size(ptr);
base_type needed_total_size = calc_blcok_total_size(size);
if (needed_total_size <= blockSize) {
if (DEBUG_MODE)
print_list();
return ptr;
}
// 当前后可能有空闲块时,可以合并后再看能否满足用户的需要
else {
// 下面这种实现不对,在mm_malloc中如果调用了split_block,那么会修改块尾部的长度值,可能篡改原来block数据
// mm_free(ptr);
// base_pt new_ptr = mm_malloc(size);
// if (!new_ptr) return NULL;
// if (DEBUG_MODE)
// printf("realloc: origin block(addr:%p, size:%d), new block(addr:%p, size:%d)\n", ptr, block_size(ptr), new_ptr, block_size(new_ptr));
// memcpy(new_ptr, ptr, blockSize - OV_SIZE);
// if (DEBUG_MODE) {
// printf("copy from old block to new block finished, total copy size:%d!\n", blockSize - OV_SIZE);
// print_list();
// }
// return new_ptr;
// 正确的实现
// 先将前后的块合并
base_pt merged_pt = merge_prev_next_block(ptr);
base_type merged_block_size = block_size(merged_pt);
base_pt final_block;
// 合并块大小不够用就直接malloc
if (merged_block_size < needed_total_size) {
insert_into_free_list_head(merged_pt);
final_block = mm_malloc(size);
memcpy(final_block, ptr, blockSize - OV_SIZE);
return final_block;
}
// 合并块够大就需要拆分
else if (merged_block_size >= (needed_total_size + EXTRA_SAPCE)) {
final_block = merged_pt;
// 必须先将块的内容复制过去,再拷贝
memcpy(final_block, ptr, blockSize - OV_SIZE);
base_pt new_block = inc_n_byte(final_block, needed_total_size);
set_block_used(final_block, needed_total_size);
set_block_free(new_block, merged_block_size - needed_total_size);
if (DEBUG_MODE)
printf("split free block(addr:%p, size:%d) into ret block(addr:%p, size:%d) and ", merged_pt, merged_block_size, merged_pt, block_size(merged_pt));
if (DEBUG_MODE)
printf("new block(addr:%p, size:%d)\n", new_block, block_size(new_block));
insert_into_free_list_head(new_block);
return final_block;
}
// 块够用但不够拆分
else {
final_block = merged_pt;
memcpy(final_block, ptr, blockSize - OV_SIZE);
return final_block;
}
}
}