C语言分配器简单分离存储,malloc lab(问题在贴中)

本文档描述了一个内存管理系统模型,包括初始化、分配、释放内存的实现。它使用隐式空闲链表和首次适配策略。分配器通过mm_init()、mm_malloc()和mm_free()函数操作内存。此外,还提出了对分配器的四个改进:增加printblocks()函数统计分配和空闲块,改变搜索策略为最佳适配,添加mm_realloc()函数以及实现简单分离存储和显式空闲链表。
摘要由CSDN通过智能技术生成

已结贴√

问题点数:20 回复次数:3

ca56232b3bbedf9a539d07f37fffb99a.gif

3144d8b7615c79d9f638db40d5689d26.gif

a218af6549b45ee526caf607ebff1358.gif

0f8df0e29816ae721419de940fb833d1.gif

malloc lab(问题在贴中)

一、内存系统模型

内存模型由memlib.c包所提供,允许我们在不干涉malloc系统包的情况下,运行分配器。其中含有以下函数:

mem_init():用malloc函数得到一个大的、双字对齐的字节数组,视为堆。

mem_heap变量:指向堆的首地址

mem_brk变量:指向堆顶,它与mem_heap之间的字节表示已分配的虚拟内存

mem_sbrk():请求额外的堆内存(让mem_brk增加),且不会收缩堆

二、分配器的函数原型

int mm_init(void);

void *mm_malloc(size_t size);

void mm_free(void *ptr);

mm_init()函数初始化分配器,若成功返回0,否则返回-1。mm_malloc()和mm_free()函数与原始的malloc和free原型和语义相同。这些函数在源文件mm.c中。

分配器对块大小使用双字边界对齐,采用教材图9-39所示的块格式,如下:

最小块大小为16(有效载荷不允许为0),空闲链表组织为一个隐式空闲链表,并具有以下恒定形式:

第一个字为填充字(不使用),后面紧跟着一个特殊的序言块,这是一个8字节的已分配块,只由一个头部和一个脚部组成。序言块是在初始化时创建,并且永不释放。

序言块后紧跟的是0个或多个普通块。

堆总是以一个特殊的结尾块来结束,这个块是一个大小为0的已分配块,只由一个头部组成。

分配器用一个static的全局变量heap_listp指向序言块。

三、操纵空闲链表的基本常数和宏

在空闲链表中操作头部和脚部要大量使用强制类型转换和指针运算,因此,预定义一些宏(macro)来访问和遍历空闲链表很有帮助,见教材图9-43。

PACK(size, alloc):将大小和已分配位打包成一个字(头部/脚部)

GET(p):返回地址p处的字

GET_SIZE(p):返回地址p处的字的大小(头部/脚部)

GET_ALLOC(p):返回地址p处的字的已分配位(头部/脚部)

bp:该指针表示块指针,即有效载荷第一个字节的地址

HDRP(bp)/FTRP(bp):返回这个块的头部/脚部地址

NEXT_BLKP(bp)/PREV_BLKP(bp):返回下一个块/前一个块的块指针

四、创建初始空闲链表

1、mm_init()从内存系统得到4个字,并将它们初始化为填充字、序言块头部、序言块脚部、结尾块。然后调用extend_heap()函数,将堆扩展CHUNKSIZE字节,并创建初始空闲块。(见mm.c)

2、extend_heap()为保持双字对齐,将请求大小向上舍入到最接近的2字倍数,然后调用mem_sbrk()请求额外的堆空间。该空间紧接在结尾块之后。

巧妙的是,结尾块就作为新空间的头部,而新空间的最后一个字作为新的结尾块。

最后,由于extend_heap()也可能被mm_malloc()调用,因此很可能旧的块是以一个空闲块结束,因此需要coalesce()函数来合并这两个空闲块。

五、释放和合并块

mm_free()用于释放一个块。该函数释放所请求的块(bp),并调用coalesce()函数来合并与之邻接的空闲块。(4种情况,见图9-40)

六、分配块

mm_malloc()函数用来分配大小为size的块。函数必须调整请求的大小,从而为头部和脚部留出空间,并满足双字对齐的要求。最小块大小为16字节(载荷不能为0)。

分配器调整了请求大小之后,会搜索空闲链表,寻找一个合适的空闲块(有多种策略,这里采用首次适配)。如果能找到,就放着这个请求块,并可选地分割出多余的部分;如果不能找到,就调用extend_heap()来扩展堆,并将请求放在这个新空闲块中。最后返回新分配的块

可选地分割:将请求块放置在空闲块的起始位置,只有当剩余部分的大于等于最小块大小时,才进行分割。

七、编写程序,测试分配器是否正确

随机生成100个整数存入链表,然后输出链表中的所有结点,最后清空整个链表。要求使用自己的动态分配器。

示例程序:test.c

#include

#include

#include

#include "memlib.h"

#include "mm.h"

struct Node

{

int element;

struct Node * next;

};

void Insert(struct Node * L, int X)

{

struct Node *P, *Q;

P = L;

while (P->next != NULL)

P = P->next;

Q = mm_malloc(sizeof(struct Node));

Q->element = X;

Q->next = P->next;

P->next = Q;

}

void PrintList(struct Node * L)

{

struct Node *P;

P = L->next;

while (P != NULL)

{

printf("%d ", P->element);

P = P->next;

}

printf("\n");

}

void ClearList(struct Node * L) // delete all nodes

{

struct Node *P;

while (L->next != NULL)

{

P = L->next;

L->next = P->next;

mm_free(P);

}

}

int main()

{

int i;

struct Node * L;

mem_init();

if (mm_init() == -1)

exit(-1);

L = mm_malloc(sizeof(struct Node)); // Header

L->next = NULL;

srand(time(NULL));

for (i = 0; i < 100; i ++)

Insert(L, rand() % 100);

PrintList(L);

ClearList(L);

}

示例程序:memlib.h

#include

void mem_init(void);

void *mem_sbrk(int incr);

示例程序:mm.h

extern int mm_init(void);

extern void *mm_malloc (size_t size);

extern void mm_free (void *ptr);

示例程序:mm.c

/*

* Simple, 32-bit and 64-bit clean allocator based on implicit free

* lists, first-fit placement, and boundary tag coalescing, as described

* in the CS:APP3e text. Blocks must be aligned to doubleword (8 byte)

* boundaries. Minimum block size is 16 bytes.

*/

#include

#include

#include

#include "mm.h"

#include "memlib.h"

/* Basic constants and macros */

#define WSIZE       4       /* Word and header/footer size (bytes) */

#define DSIZE       8       /* Double word size (bytes) */

#define CHUNKSIZE  (1<<12)  /* Extend heap by this amount (bytes) */

#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)))

/* Global variables */

static char *heap_listp = 0;  /* Pointer to first block */

/* Function prototypes for internal helper routines */

static void *extend_heap(size_t words);

static void place(void *bp, size_t asize);

static void *find_fit(size_t asize);

static void *coalesce(void *bp);

/*

* mm_init - Initialize the memory manager

*/

int mm_init(void)

{

/* Create the initial empty heap */

if ((heap_listp = mem_sbrk(4*WSIZE)) == (void *)-1)

return -1;

PUT(heap_listp, 0);                          /* Alignment padding */

PUT(heap_listp + (1*WSIZE), PACK(DSIZE, 1)); /* Prologue header */

PUT(heap_listp + (2*WSIZE), PACK(DSIZE, 1)); /* Prologue footer */

PUT(heap_listp + (3*WSIZE), PACK(0, 1));     /* Epilogue header */

heap_listp += (2*WSIZE);

/* Extend the empty heap with a free block of CHUNKSIZE bytes */

if (extend_heap(CHUNKSIZE/WSIZE) == NULL)

return -1;

return 0;

}

/*

* mm_malloc - Allocate a block with at least size bytes of payload

*/

void *mm_malloc(size_t size)

{

size_t asize;      /* Adjusted block size */

size_t extendsize; /* Amount to extend heap if no fit */

char *bp;

/* Ignore spurious requests */

if (size == 0)

return NULL;

/* Adjust block size to include overhead and alignment reqs. */

if (size <= DSIZE)

asize = 2*DSIZE;

else

asize = DSIZE * ((size + (DSIZE) + (DSIZE-1)) / DSIZE);

/* Search the free list for a fit */

if ((bp = find_fit(asize)) != NULL) {

place(bp, asize);

return bp;

}

/* No fit found. Get more memory and place the block */

extendsize = MAX(asize,CHUNKSIZE);

if ((bp = extend_heap(extendsize/WSIZE)) == NULL)

return NULL;

place(bp, asize);

return bp;

}

/*

* mm_free - Free a block

*/

void mm_free(void *bp)

{

if (bp == 0)

return;

size_t size = GET_SIZE(HDRP(bp));

PUT(HDRP(bp), PACK(size, 0));

PUT(FTRP(bp), PACK(size, 0));

coalesce(bp);

}

/*

* coalesce - Boundary tag coalescing. Return ptr to coalesced block

*/

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;

}

/*

* extend_heap - Extend heap with free block and return its block pointer

*/

static void *extend_heap(size_t words)

{

char *bp;

size_t size;

/* Allocate an even number of words to maintain alignment */

size = (words % 2) ? (words+1) * WSIZE : words * WSIZE;

if ((long)(bp = mem_sbrk(size)) == -1)

return NULL;

/* Initialize free block header/footer and the epilogue header */

PUT(HDRP(bp), PACK(size, 0));         /* Free block header */

PUT(FTRP(bp), PACK(size, 0));         /* Free block footer */

PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); /* New epilogue header */

/* Coalesce if the previous block was free */

return coalesce(bp);

}

/*

* place - Place block of asize bytes at start of free block bp

*         and split if remainder would be at least minimum block size

*/

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));

}

}

/*

* find_fit - Find a fit for a block with asize bytes

*/

static void *find_fit(size_t asize)

{

/* First-fit search */

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; /* No fit */

}

示例程序:memlib.c

/*

* memlib.c - a module that simulates the memory system.  Needed

* because it allows us to interleave calls from the student's malloc

* package with the system's malloc package in libc.

*

*/

#include

#include

#include

#include

#include

#include

#include

#include "memlib.h"

#define MAX_HEAP (20*(1<<20))  /* 20 MB */

/* Private global variables */

static char *mem_heap;     /* Points to first byte of heap */

static char *mem_brk;      /* Points to last byte of heap plus 1 */

static char *mem_max_addr; /* Max legal heap addr plus 1*/

/*

* mem_init - Initialize the memory system model

*/

void mem_init(void)

{

mem_heap = (char *)malloc(MAX_HEAP);

mem_brk = (char *)mem_heap;

mem_max_addr = (char *)(mem_heap + MAX_HEAP);

}

/*

* mem_sbrk - Simple model of the sbrk function. Extends the heap

*    by incr bytes and returns the start address of the new area. In

*    this model, the heap cannot be shrunk.

*/

void *mem_sbrk(int incr)

{

char *old_brk = mem_brk;

if ( (incr < 0) || ((mem_brk + incr) > mem_max_addr)) {

errno = ENOMEM;

fprintf(stderr, "ERROR: mem_sbrk failed. Ran out of memory...\n");

return (void *)-1;

}

mem_brk += incr;

return (void *)old_brk;

}

问题:在mm.c中增加函数printblocks(),功能为扫描整个堆,并输出已分配块和空闲块的数量。在mm_free()函数的最后调用此函数。

2、在分配器中,将搜索策略由首次适配改为最佳适配策略。

3、在mm.c中增加函数mm_realloc(),其功能与realloc()功能一致。编写一个程序测试realloc是否成功。

4、在隐式空闲链表的基础上,实现简单分离存储。

5、将隐式空闲链表改为显式空闲链表。

图片附件: 游客没有浏览图片的权限,请 登录 或 注册

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值