Files
2025-06-04 00:49:13 +08:00

298 lines
9.3 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define MAX(x, y) ((x) > (y) ? (x) : (y))
/*
* mm-naive.c - 参考实现是一个最快的、最低效率的malloc.
*
* 在这个参考实现中分配一个块仅仅是增加brk指针
* 块内部全部是载荷数据块内没有header或者footer等
* 管理用的数据信息。分配出去的块,永远不释放或者回收。
* 重分配函数realloc的实现是直接通过mm_malloc和mm_free实现的
*
* 亲们请注意:你需要把此段注释,替换成你的算法设计思想。用描述性
* 的话来说清楚。
* 请将此文件重新命名为mm_201309060024.c就是mm_你的学号.c
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <string.h>
#include "memlib.h"
#include "mm.h"
/*********************************************************
* 亲们请注意:开始之前,请把下面的信息修改为你的个人信息
********************************************************/
team_t team = {
/* 团队名字 */
"8-Bit Brainstorm",
/* 团队老大的名字 */
"Cikki",
/* 团队老大的email地址 */
"c_gh0s7@nudt.edu.cn",
/* 团队其他成员的名字 (如果没有,就空着) */
"",
/* 团队其他成员的email地址 (如果没有,就空着) */
""};
/* 基本常量和宏定义 */
#define ALIGNMENT 8 /* 将块对齐到8字节双字 */
#define ALIGN(size) \
(((size) + (ALIGNMENT - 1)) & ~0x7) /* 向上舍入到最近的8的倍数 */
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
/* 内存分配器的关键参数 */
#define WSIZE 4 /* 字word的大小 = 4字节 */
#define DSIZE 8 /* 双字double word的大小 = 8字节 */
#define CHUNKSIZE (1 << 12) /* 扩展堆时的默认大小 = 4096字节 = 4KB */
/* 用于操作头部和脚部的宏 */
#define PACK(size, alloc) ((size) | (alloc)) /* 将大小和已分配位打包成一个字 \
*/
#define GET(p) (*(unsigned int *)(p)) /* 读取指针p处的一个字 */
#define PUT(p, val) (*(unsigned int *)(p) = (val)) /* 在指针p处写入一个字 */
/* 从头部或脚部获取大小和已分配位 */
#define GET_SIZE(p) (GET(p) & ~0x7) /* 获取块大小去掉低3位的标志位 */
#define GET_ALLOC(p) (GET(p) & 0x1) /* 获取已分配位0=空闲1=已分配)*/
/* 给定块指针bp计算块的头部和脚部位置 */
#define HDRP(bp) ((char *)(bp) - WSIZE) /* 指向块头部的指针 */
#define FTRP(bp) \
((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) /* 指向块脚部的指针 */
/* 给定块指针bp计算下一个和前一个块的地址 */
#define NEXT_BLKP(bp) \
((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) /* 下一个块的指针 */
#define PREV_BLKP(bp) \
((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) /* 前一个块的指针 */
static char *heap_listp; /* 指向堆的第一个块的指针 */
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);
static void print_block(int request_id, int payload);
/*
* mm_init - 初始化内存分配器
* 创建初始空堆,包括序言块和结尾块
* 返回值成功返回0错误返回-1
*/
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;
}
/*
* extend_heap - 通过增加brk指针来扩展堆
* 参数 words: 请求的字数(以字为单位)
* 返回值指向新分配区域的指针如果出错则返回NULL
*/
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);
}
/*
* coalesce - 合并相邻的空闲块
* 参数 bp: 指向刚被释放的块的指针
* 返回值:指向合并后的块的指针
*
* 有四种情况:
* Case 1前后块都已分配
* Case 2前块已分配后块空闲
* Case 3前块空闲后块已分配
* Case 4前后块都空闲
*/
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) { // Case 1
return bp;
} else if (prev_alloc && !next_alloc) { // Case 2
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) { // Case 3
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 { // Case 4
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_malloc - 分配一个大小为size字节的块
* 参数 size: 请求的字节数
* 返回值指向新分配块的指针如果错误则返回NULL
*
* 分配策略:
* 1. 调整请求大小为8字节对齐
* 2. 搜索空闲链表找到第一个适合的块
* 3. 如果没有找到合适的块,扩展堆
*/
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;
}
/*
* mm_free - 释放一个之前分配的块
* 参数 bp: 指向要释放的块的指针
*
* 处理步骤:
* 1. 标记块为空闲(更新头部和脚部)
* 2. 合并相邻的空闲块(如果有的话)
*/
void mm_free(void *bp) {
if (bp == NULL)
return;
size_t size = GET_SIZE(HDRP(bp));
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
coalesce(bp);
}
/*
* mm_realloc - 调整一个已分配块的大小
* 参数:
* ptr - 指向旧块的指针
* size - 请求的新大小
* 返回值:指向新块的指针
*
* 处理策略:
* 1. 如果ptr为NULL等同于malloc
* 2. 如果size为0等同于free
* 3. 分配新块,复制数据,释放旧块
*/
void *mm_realloc(void *ptr, size_t size) {
if (ptr == NULL)
return mm_malloc(size);
if (size == 0) {
mm_free(ptr);
return NULL;
}
void *newptr = mm_malloc(size);
if (newptr == NULL)
return NULL;
size_t copySize = GET_SIZE(HDRP(ptr)) - DSIZE;
if (size < copySize)
copySize = size;
memcpy(newptr, ptr, copySize);
mm_free(ptr);
return newptr;
}
/*
* find_fit - 使用首次适配搜索,查找满足所需大小的空闲块
* 参数 asize: 调整后的块大小
* 返回值找到则返回块指针否则返回NULL
*/
static 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)))) {
return bp;
}
}
return NULL;
}
/*
* place - 将请求的块放置在空闲块的起始位置
* 参数:
* bp - 空闲块指针
* asize - 请求的大小
*
* 如果剩余部分足够大(>= 2*DSIZE则分割块
*/
static void place(void *bp, size_t asize) {
size_t csize = GET_SIZE(HDRP(bp));
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_heapcheck - 目前暂不支持堆检查,可以不用修改
*/
void mm_heapcheck(void) {}
/*
* 输出一块数据 - 用于heapcheck然而在此并没有什么用可以不用修改
*/
static void print_block(int request_id, int payload) {
printf("\n[%s]$BLOCK %d %d\n", __func__, request_id, payload);
}