๐ฉโ๐ปDynamic Memory Allocation in the Heap : Malloc & free
(ํ๊ณต๊ฐ์์์ ๋์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น)
๐ฉโ๐ปcomputer systems 9์ฅ
๐ฉโ๐ป implicit list , explicit list & seglist allocator
[์คํ]-[ํ]-[์ฝ๋ :[statics]-[๋ฆฌํฐ๋ด]-[ํ
์คํธ]]
๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.malloc,free,new,gc(garbage collector)
์ ๊ฐ๋
์ ํ์ฉํ์ฌ ๋ฐํ์
์์ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ๋ํด์ ์์๋ณด์.word-aligned
๋ธ๋ก์ ํ์ฉํ๋ค. malloc & free
gc
(garbage collection)size
: ํ ๋น์ ํ๊ธฐ ์ํด ํ์ํ ์ฐ์๋ ๋ฐ์ดํธ์ ํฌ๊ธฐvoid*
: size
๋ฐ์ดํธ ํฌ๊ธฐ ์ด์์ ํด๋น๋๋ ์๋ก์ด ํ ๋นํ ๋ธ๋ก์ ๊ฐ๋ฅดํค๋ ํฌ์ธํฐvoid* ptr
: free๋ฅผ ํด์ฃผ๊ธฐ ์ํ ํฌ์ธํฐp1
์ 4๋ฐ์ดํธ ํฌ๊ธฐ์ wordํ ๋นp2
๋ 5๋ฐ์ดํธ ํฌ๊ธฐ์ wordํ ๋นp3
๋ 6๋ฐ์ดํธ ํฌ๊ธฐ์ wordํ ๋นfree(p2)
๋ p2ํฌ์ธํฐ๊ฐ ๊ฐ๋ฅดํค๋ ๋ธ๋ก์ free(๋ฐํ)p4
๋ 2๋ฐ์ดํธ ํฌ๊ธฐ์ word ํ ๋น์ด(sec) ๋น malloc
๋๋ ์ด(sec)๋น ๋ง๋กํ ๋ฐ์ดํธ
์ ์ต์ํํ๋ ๊ฒ์ ๋ชฉํ๋ก ํ์!์์์๊ฐ
์ด ๊ฑธ๋ฆฌ๋๋ก, O(n)์ด ๋์ง ์๋๋ก!๐ค ์ต์ ํ๋ฅผ ์ํด thoughput (unit ๋น ์๋ฃํ request ๊ฐ์)์ memory utilization๊ฐ ์กฐ์จํ ๊ฒ์ธ๊ฐ?
internal fragmentation | external fragmentation |
---|---|
payload<block | free๊ณต๊ฐ ํ๋ํ๋ < word๊ฐ ํ ๋น๋ ๋งํ ์ฐ์๋ ๊ณต๊ฐ<=free๊ณต๊ฐ๋ค์ ์ดํฉ |
metadata, alignment, policy์ ๋ฐ๋ผ ๋ฐ์ ๊ฐ๋ฅ | ํ ๋น๋๋ free request ์์์ ๋ฐ๋ผ์ ๋ฐ์ ๊ฐ๋ฅ |
โ๏ธ ํ ๋ฐ์ดํฐ๊ตฌ์กฐ ์ ์งํ ๋ ์ค๋ฒํค๋ ์ ๋ฐ์๊ฐ๋ฅ | |
โ๏ธ alignment ์ค padding์ ์ํด ๋ฐ์๊ฐ๋ฅ | |
โ๏ธ policy : ๋ธ๋ก splitํ์ง ์๊ฒ ๋ค๊ณ ๊ฒฐ์ ์ ๋ฑ ๋ฑ | |
๐ placement policy: first-fit, next-fit, best-fit (seglist๊ฐ best-fit์ฌ์ฉ ์ ์๊ฐ ์ ์ฝ ์ ์ผ ๋ง์ด ํจ!) | |
๐ splitting policy: ํญ์ํด์ค๊น? ๊ฐ๋ํด์ค๊น? ์ฌ์ด์ฆ์ ๋ฐ๋ผ ํด์ค๊น? | |
๐ coalescing policy: immediate vs deferred (๋น์ฅ?๋์ค์?) | |
๐ ์ค๋ก์ง ์ด์ ์ request ํจํด์ ์ํด์ ๋ฐ์ ๊ฐ๋ฅํ๋ฏ๋ก ์์ธก & ํด๊ฒฐ์ด ๋น๊ต์ ์ฌ์ | ๐ซ ๋ฏธ๋ request์ ์ํด ๋ฐ์ํ๋ฏ๋ก ์์ธก & ํด๊ฒฐ์ด ์ด๋ ค์ |
p1
์์ 4๋ฐ์ดํธ word ํ ๋นp2
์์ 5๋ฐ์ดํธ word ํ ๋นp3
์์ 6๋ฐ์ดํธ word ํ ๋นp2
๋ฅผ freeํด์คp4
๋ 6๋ฐ์ดํธ. ํ ๋น๋์ง ์์ ๊ณต๊ฐ์ ํฉ์ 7๋ก ์ถฉ๋ถํ์ง๋ง ์ฐ์๋ ๊ณต๊ฐ์ ๋ถ์กฑํจ! โก๏ธ External fragmentationp0
์์ 4๋ฐ์ดํธ word๋ฅผ ํ ๋นํด์ค ๋๋ธ๋ก์ ํฌ๊ธฐ
๋ฅผ ๋ํ๋ด๋ metadata๋ฅผ ํค๋(Header)์ ์ถ๊ฐํด์ฃผ๊ธฐ (๋์ ์ถ๊ฐ์ ์ธ ํ ๋น๊ณต๊ฐ ํ์ํจ!)๐ฉโ ๐ปmalloc-lab์์ ์์ ์ธ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก
free block์ ์ถ์
ํ๋ ๋ฐฉ๋ฒ๋ค์ ๊ตฌํํด๋ณผ ๊ฒ์ด๋ค. cf. ํฌ๊ธฐ๋ณ๋ก ๋ธ๋ก sortํ๊ธฐ (RBtree์ ๊ฐ์ ๊ท ํํธ๋ฆฌ๋ฅผ ์ฌ์ฉ+ free๋ธ๋ก ๊ฐ๊ฐ์ ํฌ์ธํฐ + ๊ธธ์ด๋ฅผ key๋ก)
Splitting, boundary tags, coalescing
์ ๋ชจ๋ allocator์์ ๊ณตํต์ด๋ค.Implicit Free List
์ฒซ๋ฒ์งธ
free๋ธ๋ก ์ ํ48๋นํธ(6๋ฐ์ดํธ)
์ ํ ๋น๋์ง ์์ ๊ณต๊ฐ์ด ์์ ๋p
์์ 24๋นํธ(3๋ฐ์ดํธ)+1๋ฐ์ดํธ(metadataํฌํจ) ํฌ๊ธฐ์ ๊ณต๊ฐ์ ํ ๋นํ๊ณ ์ถ๋ค๊ณ ํ์.๊ณต๊ฐ์ ๋ค ์ฐ๊ธฐ
vs. split
๋ฅผ ํด์ผ ํจ์จ์ ์ผ๊น?free(p)
: ํฌ์ธํฐ p๊ฐ ๊ฐ๋ฅดํค๋ ์์น๋ฅผ freeํด์ฃผ๊ณ malloc(40)
: 40๋นํธ(5๋ฐ์ดํธ)+(1๋ฐ์ดํธ:metadataํฌํจ)ํฌ๊ธฐ๋ฅผ ํ ๋นํ๋ ค๊ณ ํ ๋ External fragmentation ๋ฐ์! (๊ณต๊ฐ์ ์๋๋ฐ ํ๋์ ๋ธ๋ก์ด ์๋!)free(p)
: p ํฌ์ธํฐ๊ฐ ๊ฐ๋ฅดํค๋ ์์น์ ๋ธ๋ก์ freeํ์ ๋, ๋ค์ free๋ธ๋ก๋ค๊ณผ coalesce(ํฉ)ํด์ฃผ๊ธฐ!๋
์ ๋ถ์ด๊ธฐ๐constant time coalescing ํ๋์ ๋ณด๊ธฐ
๐คํ์ฌ free๋ ๋ธ๋ก ๊ธฐ์ค์ผ๋ก ์๋ค๋ก free์ธ ๋ธ๋ก ์กด์ฌ ์ฌ๋ถ์ ๋ฐ๋ผ coalesce ์ํ ๋น๊ต
๊ตฌํ | ๋จ์ํจ |
---|---|
ํ ๋นํ๋๋ฐ ์๊ฐ๋ณต์ก๋ | O(heap์ ์๋ ๋ธ๋ก์ ์) |
freeํ๋๋ฐ ์๊ฐ๋ณต์ก๋ | O(1) |
memory utilization | placement policy์ ๋ฐ๋ผใ |
์ฌ์ฉ๋ | ํํ ์ฌ์ฉ X (ํน์ํ application ๋ชฉ์ ๋ง) |
Explicit Free List
free ๋ธ๋ก
๋ค ๊ฐ์ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํด์ ๊ฐ์ฅ ์ ์ ํ free ๋ธ๋ก ๋น ๋ฅด๊ฒ ์ฐพ๊ธฐ์ด์ค์ฐ๊ฒฐ ๋ฆฌ์คํธ
์ผ๋ก ๊ตฌํimplicitly(์์์ ์ผ๋ก)
๋ธ๋ก์ ํฌ๊ธฐ๋ฅผ ๊ฐ๊ณ free ๋ธ๋ก์ ์์น๋ฅผ ์ถ์ ํ์ง๋ง, explicit free list๋ ํ ๋น๋ ๋ธ๋ก
์ implicit free list์ ๋์ผํ ๊ตฌ์กฐ์ง๋ง free block
์ ์ ํ๋ฅผ ๊ฐ๋ฅดํฌ ํฌ์ธํฐ๋ก explicitly(๋ช
์์ ์ผ๋ก)
free ๋ธ๋ก๋ค์ ์ถ์ ํจ!
Policy | LIFO (last in first out) | Address-ordered |
---|---|---|
์ฅ์ | ๋จ์ํ๊ณ ์๊ฐ๋ณต์ก๋๊ฐ O(1) | address-order๋ณด๋ค fragmentation์ด ์ข๋ค๋ ์ฐ๊ตฌ๊ฒฐ๊ณผ ์์ |
๋จ์ | address-order๋ณด๋ค fragmentation์ด ์ฌํ๋ค๋ ์ฐ๊ตฌ๊ฒฐ๊ณผ ์์ | freeํด์ค ๋ธ๋ก ์ฝ์ ์ ์๊ฐ๋ณต์ก๋ O(n) |
freeํด์ค ๋ธ๋ก์ free list์ Head์ ์์น์ํค๊ธฐ
predecessor ๋ธ๋ก์ ์๋ผ๋ด๊ธฐ(splice) โก๏ธ ๋ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ํฉ์ณ(coalsce)์ฃผ๊ธฐ โก๏ธ ์ ๋ธ๋ก์ free list์ Head์ ์์น์ํค๊ธฐ (์์ชฝ ๋๋ค ํน์ ์์ชฝ ํ์ชฝ์๋ค๊ฐ ๋ชจ๋ ๊ฐ๋ฅ)
successor ๋ธ๋ก์ ์๋ผ๋ด๊ธฐ(splice) โก๏ธ ๋ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ํฉ์ณ(coalsce)์ฃผ๊ธฐ โก๏ธ ์ ๋ธ๋ก์ free list์ Head์ ์์น์ํค๊ธฐ
successor ๋ธ๋ก์ predecessor ๋ธ๋ก ์๋ผ๋ด๊ธฐ(splice) โก๏ธ ์ธ ๋ฉ๋ชจ๋ฆฌ ๋ธ๋ก ํฉ์ณ(coalsce)์ฃผ๊ธฐ โก๏ธ ์ ๋ธ๋ก์ free list์ Head์ ์์น์ํค๊ธฐ
๊ตฌํ | ๋น๊ต์ ๋จ์ํจ (๋ฆฌ์คํธ spliceํด์ค์ผํด์ implicit list๋ณด๋ค ์ข ๋ ๋ณต์ก) |
---|---|
ํ ๋นํ๋๋ฐ ์๊ฐ๋ณต์ก๋ | O(free ๋ธ๋ก์ ๊ฐ์) cf.implicit free๋ ๋ชจ๋ ๋ธ๋ก |
freeํ๋๋ฐ ์๊ฐ๋ณต์ก๋ | O(1) |
memory utilization | placement policy์ ๋ฐ๋ผ & larger minimum block size (next/prev) vs. implicit list |
์ฌ์ฉ๋ | ํํ ์ฌ์ฉ O (+optimization์ ๋ํจ) |
Seglist(Segregated free list) Allocators
์์์๊ฐ
์ด๋ค.๐์ฑ๋ฅ์์ฝ
: Perf index = 44 (util) + 9 (thru) = 54/100
/*
* mm.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"
// mdriver ๊ตฌ๋์ ์ํ team์ ๋ณด struct ์ค์
team_t team = {
/* Team name */
"team 1",
/* First member's full name */
"hyemin Pyo",
/* First member's email address */
"pyolovely01@gmail.com",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""};
/* ================================ Macros ===================================== */
// ๊ฐ์ข
๋ณ์,ํจ์ ์ค์
#define WSIZE 4 // word and header footer ์ฌ์ด์ฆ๋ฅผ byte๋ก.
#define DSIZE 8 // double word size๋ฅผ byte๋ก
#define CHUNKSIZE (1<<12)
/* ------------------------------ Basic Utility ------------------------------- */
#define MAX(x,y) ((x)>(y)? (x) : (y))
// size๋ฅผ packํ๊ณ ๊ฐ๋ณ word ์์ bit๋ฅผ ํ ๋น (size์ alloc์ ๋นํธ์ฐ์ฐ)
#define PACK(size,alloc) ((size)| (alloc))
/* address p์์น์ words๋ฅผ read์ write๋ฅผ ํ๋ค. */
#define GET(p) (*(unsigned int*)(p))
#define PUT(p,val) (*(unsigned int*)(p)=(val))
// address p์์น๋ก๋ถํฐ size๋ฅผ ์ฝ๊ณ field๋ฅผ ํ ๋น
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)
/* given block ptr bp, ๊ทธ๊ฒ์ header์ footer์ ์ฃผ์๋ฅผ ๊ณ์ฐ*/
#define HDRP(bp) ((char*)(bp) - WSIZE)
#define FTRP(bp) ((char*)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)
/* GIVEN block ptr bp, ์ด์ ๋ธ๋ก๊ณผ ๋ค์ ๋ธ๋ก์ ์ฃผ์๋ฅผ ๊ณ์ฐ*/
#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(((char*)(bp)-WSIZE)))
#define PREV_BLKP(bp) ((char*)(bp) - GET_SIZE(((char*)(bp) - DSIZE)))
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){ // case2 - ์ด์ ๋ธ๋ก์ ํ ๋น ์ํ, ๋ค์ ๋ธ๋ก์ ๊ฐ์ฉ์ํ. ํ์ฌ ๋ธ๋ก์ ๋ค์ ๋ธ๋ก๊ณผ ํตํฉ ๋จ.
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)); // ํค๋๋ฅผ ์ด์ ๋ธ๋ก์ BLKP๋งํผ ํตํฉ?
bp = PREV_BLKP(bp);
}
else { // case 4- ์ด์ ๋ธ๋ก๊ณผ ๋ค์ ๋ธ๋ก ๋ชจ๋ ๊ฐ์ฉ์ํ. ์ด์ ,ํ์ฌ,๋ค์ 3๊ฐ์ ๋ธ๋ก ๋ชจ๋ ํ๋์ ๊ฐ์ฉ ๋ธ๋ก์ผ๋ก ํตํฉ.
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;
}
static void *extend_heap(size_t words){ // ์ ๊ฐ์ฉ ๋ธ๋ก์ผ๋ก ํ ํ์ฅ
char *bp;
size_t size;
/* alignment ์ ์ง๋ฅผ ์ํด ์ง์ ๊ฐ์์ words๋ฅผ Allocate */
size = (words%2) ? (words+1) * WSIZE : words * WSIZE;
if ( (long)(bp = mem_sbrk(size)) == -1){
return NULL;
}
/* free block ํค๋์ ํธํฐ๋ฅผ initํ๊ณ epilogue ํค๋๋ฅผ init*/
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 ์ถ๊ฐ
/* ๋ง์ฝ prev block์ด free์๋ค๋ฉด, coalesceํด๋ผ.*/
return coalesce(bp);
}
static char *heap_listp;
/*
* mm_init - initialize the malloc package.
*/
int mm_init(void)
{
/* create ์ด๊ธฐ ๋น heap*/
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;
}
// ๋ธ๋ก์ ๋ฐํํ๊ณ ๊ฒฝ๊ณ ํ๊ทธ ์ฐ๊ฒฐ ์ฌ์ฉ -> ์์ ์๊ฐ ์์ ์ธ์ ํ ๊ฐ์ฉ ๋ธ๋ก๋ค๊ณผ ํตํฉํ๋ ํจ์๋ค
void mm_free(void *bp){
size_t size = GET_SIZE(HDRP(bp));
PUT(HDRP(bp),PACK(size,0)); // header, footer ๋ค์ free ์ํจ๋ค.
PUT(FTRP(bp), PACK(size,0));
coalesce(bp);
}
static void *find_fit(size_t asize){ // first fit ๊ฒ์์ ์ํ
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;
}
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_malloc - Allocate a block by incrementing the brk pointer. * Always allocate a block whose size is a multiple of the alignment. */
void *mm_malloc(size_t size) // ๊ฐ์ฉ ๋ฆฌ์คํธ์์ ๋ธ๋ก ํ ๋น ํ๊ธฐ
{
size_t asize; // ๋ธ๋ก ์ฌ์ด์ฆ ์กฐ์
size_t extendsize; // heap์ ๋ง๋ fit์ด ์์ผ๋ฉด ํ์ฅํ๊ธฐ ์ํ ์ฌ์ด์ฆ
char *bp;
/* ๊ฑฐ์ง๋ ์์ฒญ ๋ฌด์*/
if (size == 0) return NULL;
/* overhead, alignment ์์ฒญ ํฌํจํด์ ๋ธ๋ก ์ฌ์ด์ฆ ์กฐ์ */
if (size <= DSIZE){
asize = 2*DSIZE;
}
else {
asize = DSIZE* ( (size + (DSIZE)+ (DSIZE-1)) / DSIZE );
}
/* fit์ ๋ง๋ free ๋ฆฌ์คํธ๋ฅผ ์ฐพ๋๋ค.*/
if ((bp = find_fit(asize)) != NULL){
place(bp,asize);
return bp;
}
/* fit ๋ง๋๊ฒ ์๋ค. ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ ๊ฐ์ ธ์ block์ ์์น์ํจ๋ค.*/
extendsize = MAX(asize,CHUNKSIZE);
if ( (bp=extend_heap(extendsize/WSIZE)) == NULL){
return NULL;
}
place(bp,asize);
return bp;
}
/*
* mm_free - Freeing a block does nothing.
*/
/*
* mm_realloc - Implemented simply in terms of mm_malloc and mm_free
*/
void *mm_realloc(void *ptr, size_t size)
{
void *oldptr = ptr;
void *newptr;
size_t copySize;
newptr = mm_malloc(size);
if (newptr == NULL)
return NULL;
copySize = GET_SIZE(HDRP(oldptr));
if (size < copySize)
copySize = size;
memcpy(newptr, oldptr, copySize);
mm_free(oldptr);
return newptr;
}
๐์ฑ๋ฅ์์ฝ
: Perf index = 46 (util) + 9 (thru) = 55/100
/*
* mm.c - implicit free list based malloc package
*
* Block Format: Minimum size is 8 bytes.
* - Allocated-Block Format: [Header - Payload]
* - Free-Block Format: [Header - (Space) - Footer]
* Header/Footer: 1-word holds [block size, prev-bit, alloc-bit]
* - prev-bit: is previous block allocated.
* - alloc-bit: is current block allocated.
* List Format: implicit free list
* [Head-Block[1] | Regular-Blocks(F/A) ...| Tail-Block[1]]
* Placement Policy: using first-fit algorithm.
* Split Policy: always split if remainder is greater than 8 bytes
* Coalescing Policy: bi-direction coalescing after each unallocation
*
* realloc: split if new size is less than the block size by 8 bytes
* allocate-copy-free if new size is greater than block size
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "mm.h"
#include "memlib.h"
/* =============================================================================== */
team_t team = {
/*team*/
"team 1",
/* First member's full name */
"Hyemin Pyo",
/* First member's email address */
"pyolovely01@gmail.com",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""
};
/* ========================== Function Prototype =============================== */
inline static void* resize_block(void*, size_t);
inline static void* reallocate_block(void*, size_t);
inline static void* extend_heap(size_t);
inline static void* first_fit(size_t);
inline static void* best_fit(size_t);
inline static void* find_fit(size_t);
inline static void place(void*, size_t);
inline static void* coalesce(void*);
inline static void set_prev_bit(void*, size_t);
/* ========================== Compilation Flags =============================== */
// #define DEBUG /* uncomment to turn-on heap checker */
#ifdef DEBUG
static void mm_check(int line);
#define heap_check(line) (mm_check(line))
#else
#define heap_check(line)
#endif
/* ================================ Macros ===================================== */
#define WSIZE 4 /* Word size in bytes */
#define DSIZE 8 /* Double word size in bytes */
#define CHUNKSIZE (1<<8) /* Minimum heap allocation size */
#define MIN_BLOCK_SIZE 8 /* Minimum block size */
#define ALIGNMENT 8 /* Payload Alignment */
#define WTYPE u_int32_t /* Word type */
#define BYTE char /* Byte type */
/* ------------------------------ Basic Utility ------------------------------- */
/* Move the address ptr by offset bytes */
#define MOVE_BYTE(ptr, offset) ((WTYPE *)((BYTE *)(ptr) + (offset)))
/* Move the address ptr by offset words */
#define MOVE_WORD(ptr, offset) ((WTYPE *)(ptr) + (offset))
/* Read a word from address ptr */
#define READ_WORD(ptr) (*(WTYPE *)(ptr))
/* Write a word value to address ptr */
#define WRITE_WORD(ptr, value) (*(WTYPE *)(ptr) = (value))
/* rounds up size (in bytes) to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
/* Get the maximum of x and y */
#define MAX(x, y) ((x) > (y)? (x) : (y))
/* Get the minimum of x and y */
#define MIN(x, y) ((x) < (y)? (x) : (y))
/* ----------------------- Header/Footer Macros ---------------------------- */
/* Pack the size, prev-allocated and allocation bits into a word */
#define PACK(size, prev, alloc) ((size) | (prev << 1) | (alloc))
/* Read the size from header/footer word at address Hptr */
#define READ_SIZE(Hptr) (READ_WORD(Hptr) & ~0x7)
/* Read the allocation-bit from header/footer word at address Hptr */
#define READ_ALLOC(Hptr) (READ_WORD(Hptr) & 0x1)
/* Read the prev-allocated-bit from header/footer word at address Hptr */
#define READ_PREV_ALLOC(Hptr) ((READ_WORD(Hptr) & 0x2) >> 1)
/* Write the size, prev-allocated and allocation bits to the word at address Hptr */
#define WRITE(Hptr, size, prev, alloc)\
(WRITE_WORD((Hptr), PACK((size), (prev), (alloc))))
/* Write the size to the word at address Hptr */
#define WRITE_SIZE(Hptr, size)\
(WRITE((Hptr), (size), READ_PREV_ALLOC(Hptr), READ_ALLOC(Hptr)))
/* Write allocation-bit to the word at address Hptr */
#define WRITE_ALLOC(Hptr, alloc)\
(WRITE((Hptr), READ_SIZE(Hptr), READ_PREV_ALLOC(Hptr), alloc))
/* Write prev-allocated-bit to the word at address Hptr */
#define WRITE_PREV_ALLOC(Hptr, prev)\
(WRITE((Hptr), READ_SIZE(Hptr), prev, READ_ALLOC(Hptr)))
/* ---------------------------- Payload Macros ------------------------------ */
/* Get the header-word pointer from the payload pointer pp */
#define HEADER(pp) (MOVE_WORD(pp, -1))
/* Get the footer-word pointer from the payload pointer pp */
#define FOOTER(pp) (MOVE_BYTE(pp, (BLOCK_SIZE(pp) - DSIZE)))
/* Get next block payload pointer from pp (current payload pointer) */
#define NEXT_BLOCK(pp) (MOVE_BYTE(pp, BLOCK_SIZE(pp)))
/* Get previous block payload pointer from pp (current payload pointer) */
#define PREV_BLOCK(pp) (MOVE_BYTE(pp, - READ_SIZE(MOVE_WORD(pp, -2))))
/* Read the block size at the payload pp */
#define BLOCK_SIZE(pp) (READ_SIZE(HEADER(pp)))
/* Read the payload size at pp */
#define PAYLOAD_SIZE(pp) (BLOCK_SIZE(pp) - WSIZE)
/* Gets the block allocation status (alloc-bit) */
#define GET_ALLOC(pp) (READ_ALLOC(HEADER(pp)))
/* Gets the previous block allocation status (prev-alloc-bit) */
#define GET_PREV_ALLOC(pp) (READ_PREV_ALLOC(HEADER(pp)))
/* Check if the block at the payload pp is free */
#define IS_FREE(pp) (!(GET_ALLOC(pp)))
/* Check if the previous block of the payload pp is free */
#define IS_PREV_FREE(pp) (!(GET_PREV_ALLOC(pp)))
/* Sets the size, prev-allocated and allocation-bit to header of block at pp */
#define SET_HEADER(pp, size, prev, alloc) ((WRITE(HEADER(pp),(size),(prev),(alloc))))
/* Sets the size to header of block at pp */
#define SET_HEADER_SIZE(pp, size) ((WRITE_SIZE(HEADER(pp),(size))))
/* Sets the allocation-bit to header of block at pp */
#define SET_HEADER_ALLOC(pp, alloc) ((WRITE_ALLOC(HEADER(pp),(alloc))))
/* Sets the prev-allocated-bit to header of block at pp */
#define SET_HEADER_PREV_ALLOC(pp, prev) ((WRITE_PREV_ALLOC(HEADER(pp),(prev))))
/* Sets the size, prev-allocated and allocation-bit to header/footer of block at pp */
#define SET_INFO(pp, size, prev, alloc)\
((WRITE(HEADER(pp),(size),(prev),(alloc))), \
(WRITE(FOOTER(pp),(size),(prev),(alloc))))
/* Sets the size to header/footer of block at pp */
#define SET_SIZE(pp, size) (SET_INFO((pp),(size),GET_PREV_ALLOC(pp),GET_ALLOC(pp)))
/* Sets the allocation-bit to header/footer of block at pp */
#define SET_ALLOC(pp, alloc) (SET_INFO((pp),BLOCK_SIZE(pp),GET_PREV_ALLOC(pp),(alloc)))
/* Sets the prev-allocated-bit to header/footer of block at pp */
#define SET_PREV_ALLOC(pp, prev) (SET_INFO((pp),BLOCK_SIZE(pp),(prev),GET_ALLOC(pp)))
/* ======================= Private Global Variables ============================== */
// private global variable
static WTYPE* heap_listp; /* pointer to first block payload */
/* =========================== Public Functions ================================== */
/*
* Initialize the malloc package.
* return 0 on success, -1 on error.
*/
int mm_init(void) {
/* Create the initial empty heap */
if ((heap_listp = mem_sbrk(DSIZE)) == (WTYPE*)-1) return -1;
WRITE(heap_listp, 0,0,1); /* Head Word */
WRITE(heap_listp + 1, 0,1,1); /* Tail Word */
heap_listp += 2;
/* Extend the empty heap with a free block of CHUNKSIZE bytes */
if (extend_heap(CHUNKSIZE) == NULL) return -1;
heap_check(__LINE__);
return 0;
}
/*
* Allocate an aligned block of memory of at least size bytes
* Return address of allocated block on success, NULL on error.
*/
void* mm_malloc(size_t size) {
if (size == 0) return NULL;
void* pp; /* Payload Pointer */
size = ALIGN(size + WSIZE); /* Add header word */
/* Search the free list for a fit */
if ((pp = find_fit(size)) == NULL) {
/* No fit found, request a block from the memory */
pp = extend_heap(MAX(size, CHUNKSIZE));
if (pp == NULL) return NULL;
}
place(pp, size);
heap_check(__LINE__);
return pp;
}
/*
* Free the allocated block at ptr, and coalesce it.
*/
void mm_free(void* ptr) {
SET_ALLOC(ptr, 0);
set_prev_bit(NEXT_BLOCK(ptr), 0);
coalesce(ptr);
heap_check(__LINE__);
}
/*
* # ptr = NULL : allocate block of the given size.
* # size = 0 : free the given block, return NULL.
* # else: resize the allocated block at ptr.
*
* Return address of the reallocated block, NULL on error.
*/
void* mm_realloc(void* ptr, size_t size) {
if (ptr == NULL){
return mm_malloc(size);
}else if (size == 0){
mm_free(ptr);
return NULL;
}else{
ptr = resize_block(ptr, size);
heap_check(__LINE__);
return ptr;
}
}
/* =========================== Private Functions ================================== */
/*
* Resize the allocated block at pp to have size bytes
* Return address of the resized block, NULL on error.
*/
static void* resize_block(void* pp, size_t size) {
size_t asize = MAX(MIN_BLOCK_SIZE, ALIGN(size + WSIZE));
size_t bsize = BLOCK_SIZE(pp);
size_t csize = bsize - asize;
if (asize > bsize) return reallocate_block(pp, size);
if (csize >= MIN_BLOCK_SIZE){
SET_HEADER_SIZE(pp, asize);
void* free_part = NEXT_BLOCK(pp);
SET_INFO(free_part, csize, 1, 0);
set_prev_bit(NEXT_BLOCK(free_part), 0);
coalesce(free_part);
}
return pp;
}
/*
* Allocate block of the given size, copy content, free old block
* Return address of the new block, NULL on error.
*/
static void* reallocate_block(void* ptr, size_t size) {
void *newptr = mm_malloc(size);
if (newptr == NULL) return NULL;
size_t copy_size = MIN(PAYLOAD_SIZE(ptr), size);
memcpy(newptr, ptr, copy_size);
mm_free(ptr);
return newptr;
}
/**
* Add free block with aligned size to the end of the heap.
* Return address of the added free block, NULL on error.
*/
void* extend_heap(size_t size) {
WTYPE* pp;
size = ALIGN(size);
if ((long)(pp = mem_sbrk(size)) == -1) return NULL;
size_t prev_bit = GET_PREV_ALLOC(pp);
SET_INFO(pp, size, prev_bit, 0); /* Initialize a free block */
SET_HEADER(NEXT_BLOCK(pp), 0,0,1); /* New Tail Word */
if (!prev_bit) return coalesce(pp); /* coalesce if previous block is free */
return pp;
}
/* Find the first block greater than or equal to size
* Return address of the first-fit, NULL if no-fit.
*/
static void* first_fit(size_t size) {
void* pp;
for (pp = heap_listp; BLOCK_SIZE(pp) > 0; pp = NEXT_BLOCK(pp)) {
if (IS_FREE(pp) && (size <= BLOCK_SIZE(pp))) return pp;
}
return NULL;
}
/* Find the smallest block greater than or equal to size
* Return address of the best-fit, NULL if no-fit.
*/
static void* best_fit(size_t size) {
void* pp;
void* best = NULL;
size_t best_size = __SIZE_MAX__;
for (pp = heap_listp; BLOCK_SIZE(pp) > 0; pp = NEXT_BLOCK(pp)) {
size_t curr_size = BLOCK_SIZE(pp);
if (IS_FREE(pp) && (size <= curr_size) && (curr_size < best_size)){
best = pp;
}
}
return best;
}
/**
* Find a free block with size greater than or equal to size.
* Return address of a fit-block, NULL if no fit.
*/
static void* find_fit(size_t size) {
return first_fit(size);
}
/**
* Allocate the free block at pp.
* Split the block if the remainder is greater than MIN_BLOCK_SIZE.
*/
static void place(void *pp, size_t size) {
size_t bsize = BLOCK_SIZE(pp);
if (bsize < (size + MIN_BLOCK_SIZE)){
SET_ALLOC(pp, 1);
set_prev_bit(NEXT_BLOCK(pp), 1);
}else{
SET_HEADER(pp, size, GET_PREV_ALLOC(pp), 1);
pp = NEXT_BLOCK(pp);
SET_INFO(pp, bsize-size, 1, 0);
}
}
/**
* Coalesce the current block with its free previous and/or next blocks.
* Return the address of the coalesced free-block.
*/
static void* coalesce(void *pp) {
size_t prev_alloc = GET_PREV_ALLOC(pp);
size_t next_alloc = GET_ALLOC(NEXT_BLOCK(pp));
size_t size = BLOCK_SIZE(pp);
size_t prev_bit = prev_alloc;
if (prev_alloc && next_alloc) return pp;
if (!next_alloc) size += BLOCK_SIZE(NEXT_BLOCK(pp));
if (!prev_alloc) {
pp = PREV_BLOCK(pp);
size += BLOCK_SIZE(pp);
prev_bit = GET_PREV_ALLOC(pp);
}
SET_INFO(pp, size, prev_bit, 0);
return pp;
}
/**
* Sets the prev-bit in the (free/allocated) block at pp.
*/
static void set_prev_bit(void* pp, size_t prev_bit){
if (IS_FREE(pp)){
SET_PREV_ALLOC(pp, prev_bit);
}else{
SET_HEADER_PREV_ALLOC(pp, prev_bit);
}
}
/* ========================== Debugging Functions =============================== */
#ifdef DEBUG
/**
* Heap Consistency Checker, checks for:
* - head and tail words of the heap
* - block header and footer equality for free blocks
* - block size >= minimum size
* - payload alignment
* - coalescing (no contiguous free blocks)
* - prev-bit correctness.
* - total heap size
*/
static void mm_check(int line){
WTYPE* ptr = mem_heap_lo();
WTYPE* end_ptr = MOVE_BYTE(ptr, mem_heapsize()) - 1;
// Check head word (size = 0, prev is free, allocated)
if (READ_SIZE(ptr) != 0){
printf("Error at %d: head-word size = %u\n",line, READ_SIZE(ptr));
}
if (READ_ALLOC(ptr) != 1){
printf("Error at %d: head-word is not allocated\n",line);
}
if (READ_PREV_ALLOC(ptr)){
printf("Error at %d: head-word is prev is allocated\n",line);
}
// Check tail word (size = 0, allocated)
if (READ_SIZE(end_ptr) != 0){
printf("Error at %d: tail-word size = %u\n",line, READ_SIZE(end_ptr));
}
if (READ_ALLOC(end_ptr) != 1){
printf("Error at %d: tail-word is not allocated\n",line);
}
size_t heap_size = DSIZE;
int prev_free = 0;
// Check regular blocks
for (ptr = heap_listp; ptr < end_ptr; ptr = NEXT_BLOCK(ptr)){
// check header and footer equality
if (IS_FREE(ptr) && (READ_WORD(HEADER(ptr)) != READ_WORD(FOOTER(ptr)))){
printf("Error at %d: at block %p => header = %u, footer = %u\n",
line, ptr, READ_WORD(HEADER(ptr)), READ_WORD(FOOTER(ptr)));
}
// check that block size >= minimum size
if (BLOCK_SIZE(ptr) < MIN_BLOCK_SIZE){
printf("Error at %d: block %p has size < min size, (%u < %u)\n",
line, ptr, BLOCK_SIZE(ptr), MIN_BLOCK_SIZE);
}
// check payload alignment
if((unsigned) ptr % ALIGNMENT){
printf("Error at %d: block %p is not aligned to %d\n",
line, ptr, ALIGNMENT);
}
// check coalescing.
if (prev_free && IS_FREE(ptr)){
printf("Error at %d: two contiguous free blocks not coalesced\n", line);
}
// check prev-allocated bit
if (prev_free != IS_PREV_FREE(ptr)){
printf("Error at %d: block %p prev-bit is incorrect\n", line, ptr);
}
prev_free = IS_FREE(ptr);
heap_size += BLOCK_SIZE(ptr);
}
// check total heap size
if (heap_size != mem_heapsize()){
printf("Error at %d: heap size not accurate, %u should be %u\n",
line, heap_size, mem_heapsize());
}
}
#endif
๐์ฑ๋ฅ์์ฝ
: Perf index = 46 (util) + 40 (thru) = 86/100
/* mm.c
*
* Blocks are aligned to double-word boundaries. This
* yields 8-byte aligned blocks on a 32-bit processor, and 16-byte aligned
* blocks on a 64-bit processor. However, 16-byte alignment is stricter
* than necessary; the assignment only requires 8-byte alignment. The
* minimum block size taken is 4 words.
* This allocator uses the size of a pointer, e.g., sizeof(void *), to
* define the size of a word. This allocator also uses the standard
* type uintptr_t to define unsigned integers that are the same size
* as a pointer, i.e., sizeof(uintptr_t) == sizeof(void *).
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "memlib.h"
#include "mm.h"
/*********************************************************
* NOTE TO STUDENTS: Before you do anything else, please
* provide your team information in the following struct.
********************************************************/
team_t team = {
"team 1",
"Hyemin Pyo",
"pyolovely01@gmail.com",
"",
"",
};
//* Basic constants and macros: */
#define WSIZE sizeof(void *) /* Word and header/footer size (bytes) */
#define DSIZE (2 * WSIZE) /* Doubleword size (bytes) */
#define CHUNKSIZE (1 << 12) /* Extend heap by this amount (bytes) */
/*Max value of 2 values*/
#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) (*(uintptr_t *)(p))
#define PUT(p, val) (*(uintptr_t *)(p) = (val))
/* Read the size and allocated fields from address p */
#define GET_SIZE(p) (GET(p) & ~(DSIZE - 1))
#define GET_ALLOC(p) (GET(p) & 0x1)
/* Given block ptr bp, compute address of its header and footer */
#define HDRP(bp) ((void *)(bp) - WSIZE)
#define FTRP(bp) ((void *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)
/* Given block ptr bp, compute address of next and previous blocks */
#define NEXT_BLKP(bp) ((void *)(bp) + GET_SIZE(HDRP(bp)))
#define PREV_BLKP(bp) ((void *)(bp) - GET_SIZE((void *)(bp) - DSIZE))
/* Given ptr in free list, get next and previous ptr in the list */
/* bp is address of the free block. Since minimum Block size is 16 bytes,
we utilize to store the address of previous block pointer and next block pointer.
*/
#define GET_NEXT_PTR(bp) (*(char **)(bp + WSIZE))
#define GET_PREV_PTR(bp) (*(char **)(bp))
/* Puts pointers in the next and previous elements of free list */
#define SET_NEXT_PTR(bp, qp) (GET_NEXT_PTR(bp) = qp)
#define SET_PREV_PTR(bp, qp) (GET_PREV_PTR(bp) = qp)
/* Global declarations */
static char *heap_listp = 0;
static char *free_list_start = 0;
/* Function prototypes for internal helper routines */
static void *coalesce(void *bp);
static void *extend_heap(size_t words);
static void *find_fit(size_t asize);
static void place(void *bp, size_t asize);
/* Function prototypes for maintaining free list*/
static void insert_in_free_list(void *bp);
static void remove_from_free_list(void *bp);
/* Function prototypes for heap consistency checker routines: */
static void checkblock(void *bp);
static void checkheap(bool verbose);
static void printblock(void *bp);
/**
* Initialize the memory manager.
* @param - void no parameter passed in
* @return - int 0 for success or -1 for failure
*/
int mm_init(void) {
/* Create the initial empty heap. */
if ((heap_listp = mem_sbrk(8*WSIZE)) == NULL)
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 */
free_list_start = heap_listp + 2*WSIZE;
/* Extend the empty heap with a free block of minimum possible block size */
if (extend_heap(4) == NULL){
return -1;
}
return 0;
}
/*
* Requires:
* size of memory asked by the programmer.
*
* Effects:
* Allocate a block with at least "size" bytes of payload, unless "size" is
* zero. Returns the address of this block if the allocation was successful
* and NULL otherwise.
*/
void *mm_malloc(size_t size)
{
size_t asize; /* Adjusted block size */
size_t extendsize; /* Amount to extend heap if no fit */
void *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);
}
/*
* Requires:
* "bp" is either the address of an allocated block or NULL.
*
* Effects:
* Free a block.
*/
void mm_free(void *bp){
size_t size;
/* Ignore spurious requests. */
if (bp == NULL)
return;
/* Free and coalesce the block. */
size = GET_SIZE(HDRP(bp));
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
coalesce(bp);
}
/*
* Requires:
* "ptr" is either the address of an allocated block or NULL.
*
* Effects:
* Reallocates the block "ptr" to a block with at least "size" bytes of
* payload, unless "size" is zero.
* If "size" is zero, frees the block "ptr" and returns NULL.
* If the block "ptr" is already a block with at
* least "size" bytes of payload, then "ptr" may optionally be returned.
* Further if requested size is greater than the current block size at pointer bp
* and we have the next block as empty with sum of current block size and next block (which happens to be empty)
* then we dont need call malloc but just combine current block and next block to resize them so as to
* satisfy the requested realloc size.
* If nothing can be done then a new block is allocated (using malloc) and the contents of the old block
* "ptr" are copied to that new block. Returns the address of this new
* block if the allocation was successful and NULL otherwise.
*/
void *mm_realloc(void *bp, size_t size){
if((int)size < 0)
return NULL;
else if((int)size == 0){
mm_free(bp);
return NULL;
}
else if(size > 0){
size_t oldsize = GET_SIZE(HDRP(bp));
size_t newsize = size + 2 * WSIZE; // 2 words for header and footer
/*if newsize is less than oldsize then we just return bp */
if(newsize <= oldsize){
return bp;
}
/*if newsize is greater than oldsize */
else {
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t csize;
/* next block is free and the size of the two blocks is greater than or equal the new size */
/* then we only need to combine both the blocks */
if(!next_alloc && ((csize = oldsize + GET_SIZE( HDRP(NEXT_BLKP(bp)) ))) >= newsize){
remove_from_free_list(NEXT_BLKP(bp));
PUT(HDRP(bp), PACK(csize, 1));
PUT(FTRP(bp), PACK(csize, 1));
return bp;
}
else {
void *new_ptr = mm_malloc(newsize);
place(new_ptr, newsize);
memcpy(new_ptr, bp, newsize);
mm_free(bp);
return new_ptr;
}
}
}else
return NULL;
}
/*
* Requires:
* "bp" is the address of a newly freed block.
*
* Effects:
* Perform boundary tag coalescing.
* Removes and inserts appropiate free block pointers to the explicit free list
* Returns the address of the coalesced block.
*/
static void *coalesce(void *bp){
//if previous block is allocated or its size is zero then PREV_ALLOC will be set.
size_t NEXT_ALLOC = GET_ALLOC( HDRP(NEXT_BLKP(bp)) );
size_t PREV_ALLOC = GET_ALLOC( FTRP(PREV_BLKP(bp)) ) || PREV_BLKP(bp) == bp;
size_t size = GET_SIZE(HDRP(bp));
/* Next block is only free */
if (PREV_ALLOC && !NEXT_ALLOC) {
size += GET_SIZE( HDRP(NEXT_BLKP(bp)) );
remove_from_free_list(NEXT_BLKP(bp));
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
}
/* Prev block is only free */
else if (!PREV_ALLOC && NEXT_ALLOC) {
size += GET_SIZE( HDRP(PREV_BLKP(bp)) );
bp = PREV_BLKP(bp);
remove_from_free_list(bp);
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
}
/* Both blocks are free */
else if (!PREV_ALLOC && !NEXT_ALLOC) {
size += GET_SIZE( HDRP(PREV_BLKP(bp)) ) + GET_SIZE( HDRP(NEXT_BLKP(bp)) );
remove_from_free_list(PREV_BLKP(bp));
remove_from_free_list(NEXT_BLKP(bp));
bp = PREV_BLKP(bp);
PUT(HDRP(bp), PACK(size, 0));
PUT(FTRP(bp), PACK(size, 0));
}/* lastly insert bp into free list and return bp */
insert_in_free_list(bp);
return bp;
}
/*
* Requires:
* None.
*
* Effects:
* Extend the heap with a free block and return that block's address.
*/
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;
//Since minimum block size given to us is 4 words (ie 16 bytes)
if (size < 16){
size = 16;
}
/* call for more memory space */
if ((int)(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 bp with next and previous blocks */
return coalesce(bp);
}
/*
* Requires:
* Size of memory to find.
* Effects:
* Finds a fit for a block with "asize" bytes from the free list.
* Extends the heap in some special cases.
* And Returns that block's address
* or NULL if no suitable block was found.
*/
static void *find_fit(size_t asize){
void *bp;
static int last_malloced_size = 0;
static int repeat_counter = 0;
if( last_malloced_size == (int)asize){
if(repeat_counter>30){
int extendsize = MAX(asize, 4 * WSIZE);
bp = extend_heap(extendsize/4);
return bp;
}
else
repeat_counter++;
}
else
repeat_counter = 0;
for (bp = free_list_start; GET_ALLOC(HDRP(bp)) == 0; bp = GET_NEXT_PTR(bp) ){
if (asize <= (size_t)GET_SIZE(HDRP(bp)) ) {
last_malloced_size = asize;
return bp;
}
}
return NULL;
}
/*
* Requires:
* "bp" is the address of a free block that is at least "asize" bytes.
* Effects:
* Place a block of "asize" bytes at the start of the free block "bp" and
* split that block if the remainder would be at least the minimum block
* size.
*/
static void place(void *bp, size_t asize){
size_t csize = GET_SIZE(HDRP(bp));
if ((csize - asize) >= 4 * WSIZE) {
PUT(HDRP(bp), PACK(asize, 1));
PUT(FTRP(bp), PACK(asize, 1));
remove_from_free_list(bp);
bp = NEXT_BLKP(bp);
PUT(HDRP(bp), PACK(csize-asize, 0));
PUT(FTRP(bp), PACK(csize-asize, 0));
coalesce(bp);
}
else {
PUT(HDRP(bp), PACK(csize, 1));
PUT(FTRP(bp), PACK(csize, 1));
remove_from_free_list(bp);
}
}
/*Inserts the free block pointer int the free_list*/
static void insert_in_free_list(void *bp){
SET_NEXT_PTR(bp, free_list_start);
SET_PREV_PTR(free_list_start, bp);
SET_PREV_PTR(bp, NULL);
free_list_start = bp;
}
/*Removes the free block pointer int the free_list*/
static void remove_from_free_list(void *bp){
if (GET_PREV_PTR(bp))
SET_NEXT_PTR(GET_PREV_PTR(bp), GET_NEXT_PTR(bp));
else
free_list_start = GET_NEXT_PTR(bp);
SET_PREV_PTR(GET_NEXT_PTR(bp), GET_PREV_PTR(bp));
}
/*
* The remaining routines are heap consistency checker routines.
*/
/*
* Requires:
* "bp" is the address of a block.
*
* Effects:
* Perform a minimal check on the block "bp".
*/
static void
checkblock(void *bp)
{
if ((uintptr_t)bp % DSIZE)
printf("Error: %p is not doubleword aligned\n", bp);
if (GET(HDRP(bp)) != GET(FTRP(bp)))
printf("Error: header does not match footer\n");
}
/*
* Requires:
* None.
*
* Effects:
* Perform a minimal check of the heap for consistency.
*/
void
checkheap(bool verbose)
{
void *bp;
if (verbose)
printf("Heap (%p):\n", heap_listp);
if (GET_SIZE(HDRP(heap_listp)) != DSIZE ||
!GET_ALLOC(HDRP(heap_listp)))
printf("Bad prologue header\n");
checkblock(heap_listp);
for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = (void *)NEXT_BLKP(bp)) {
if (verbose)
printblock(bp);
checkblock(bp);
}
if (verbose)
printblock(bp);
if (GET_SIZE(HDRP(bp)) != 0 || !GET_ALLOC(HDRP(bp)))
printf("Bad epilogue header\n");
}
/*
* Requires:
* "bp" is the address of a block.
*
* Effects:
* Print the block "bp".
*/
static void
printblock(void *bp)
{
bool halloc, falloc;
size_t hsize, fsize;
checkheap(false);
hsize = GET_SIZE(HDRP(bp));
halloc = GET_ALLOC(HDRP(bp));
fsize = GET_SIZE(FTRP(bp));
falloc = GET_ALLOC(FTRP(bp));
if (hsize == 0) {
printf("%p: end of heap\n", bp);
return;
}
printf("%p: header: [%zu:%c] footer: [%zu:%c]\n", bp,
hsize, (halloc ? 'a' : 'f'),
fsize, (falloc ? 'a' : 'f'));
}
/*
* The last lines of this file configures the behavior of the "Tab" key in
* emacs. Emacs has a rudimentary understanding of C syntax and style. In
* particular, depressing the "Tab" key once at the start of a new line will
* insert as many tabs and/or spaces as are needed for proper indentation.
*/
/* Local Variables: */
/* mode: c */
/* c-default-style: "bsd" */
/* c-basic-offset: 8 */
/* c-continued-statement-offset: 4 */
/* indent-tabs-mode: t */
/* End: */
๐์ฑ๋ฅ์์ฝ
: Perf index = 58 (util) + 40 (thru) = 98/100
/*
* mm.c
*
* Block Format: Minimum size is 16 bytes.
* - Free-Block Format: [Header - Pred - Succ - (Empty) - Footer]
* - Allocated-Block Format: [Header - Payload - Footer]
* - Header/Footer: 1-word holds size of the block and allocation-bit at LSB(Least Significant Bit)
* - Pred: 1-word holds the address of the predecessor free-block.
* - Succ: 1-word holds the address of the successor free-block.
*
* List Format: array of 8 explicit-free lists
* Heap Format: [seglist-array[8] | Head-Block[1] | Regular-Blocks ...| Tail-Block[1]]
* - Head/Tail: 1-word allocated block of zero size.
*
* Placement Policy: using best-fit algorithm.
* Split Policy: split if remainder is greater than 16 bytes
* Coalescing Policy: bi-direction coalescing for free-blocks and allocated-blocks
* Heap Extension Policy:
* - if the size is greater than CHUNK_SIZE: extend by one block of the given size
* - else: extend the heap by a few blocks each of the given size.
*
* realloc:
* - if new-size is greater than current-size: expand the block if it can be expanded,
* otherwise, reallocate the block (allocate - copy - free).
* - if the new-size is less than current size by 64 byte at least then split.
*
* NOTE: Coalescing is not strict, there are some free blocks not coalesced just to keep
* a variety of sizes in the seglist.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "mm.h"
#include "memlib.h"
/* =============================================================================== */
team_t team = {
/* Team name */
"pyotato",
/* First member's full name */
"Hyemin PYo",
/* First member's email address */
"pyolovely01@gmail.com",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""
};
/* ========================== Function Prototype =============================== */
inline static void* resize_block(void*, size_t);
inline static void* reallocate_block(void*, size_t);
inline static int can_expand(void*, size_t);
inline static void* expand_block(void*, size_t);
inline static void chop_block(void*, size_t);
inline static void* extend_heap(size_t);
inline static void* first_fit(void*, size_t);
inline static void* best_fit(void*, size_t);
inline static void* find_fit(size_t);
inline static void* place(void*, size_t);
inline static void* coalesce(void*);
inline static void link_block(void*);
inline static void unlink_block(void*);
inline static int seg_index(size_t);
/* ========================== Compilation Flags =============================== */
// #define DEBUG /* uncomment to turn-on heap checker */
#ifdef DEBUG
static void mm_check(int);
static void check_seglist(int, int);
static int check_free_list(int, int);
#define heap_check(line) (mm_check(line))
#else
#define heap_check(line)
#endif
//NOTE at 236: two contiguous free blocks not coalesced ์์ผ๋ก heap ์ฒดํฌ ๊ฐ๋ฅ
/* ================================ Macros ===================================== */
#define WSIZE 4 /* Word size in bytes */
#define DSIZE 8 /* Double word size in bytes */
#define CHUNKSIZE (1<<8) /* Minimum heap allocation size */
#define MIN_BLOCK_SIZE 16 /* Minimum block size */
#define ALIGNMENT 8 /* Payload Alignment */
#define SEGLIST_NUM 8 /* The Number of lists in the seglist */
#define WTYPE u_int32_t /* Word type */
#define BYTE char /* Byte type */
/* ------------------------------ Basic Utility ------------------------------- */
/* Move the address ptr by offset bytes */
#define MOVE_BYTE(ptr, offset) ((WTYPE *)((BYTE *)(ptr) + (offset)))
/* Move the address ptr by offset words */
#define MOVE_WORD(ptr, offset) ((WTYPE *)(ptr) + (offset))
/* Read a word from address ptr */
#define READ_WORD(ptr) (*(WTYPE *)(ptr))
/* Write a word value to address ptr */
#define WRITE_WORD(ptr, value) (*(WTYPE *)(ptr) = (value))
/* rounds up size (in bytes) to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
/* Get the maximum of x and y */
#define MAX(x, y) (((x) > (y))? (x) : (y))
/* Get the minimum of x and y */
#define MIN(x, y) (((x) < (y))? (x) : (y))
/* ----------------------- Header/Footer Macros ---------------------------- */
/* Pack the size and allocated-bit into a word */
#define PACK(size, alloc) ((size) | (alloc))
/* Read the size from header/footer word at address Hptr */
#define READ_SIZE(Hptr) (READ_WORD(Hptr) & ~0x7)
/* Read the allocated-bit from header/footer word at address Hptr */
#define READ_ALLOC(Hptr) (READ_WORD(Hptr) & 0x1)
/* Write the size and allocation-bit to the word at address Hptr */
#define WRITE(Hptr, size, alloc) (WRITE_WORD((Hptr), PACK((size), (alloc))))
/* Write the size to the word at address Hptr */
#define WRITE_SIZE(Hptr, size) (WRITE((Hptr), (size), READ_ALLOC(Hptr)))
/* Write allocation-bit to the word at address Hptr */
#define WRITE_ALLOC(Hptr, alloc) (WRITE((Hptr), READ_SIZE(Hptr), (alloc)))
/* ---------------------------- Payload Macros ------------------------------ */
/* Get the header-word pointer from the payload pointer pp */
#define HEADER(pp) (MOVE_WORD(pp, -1))
/* Get the footer-word pointer from the payload pointer pp */
#define FOOTER(pp) (MOVE_BYTE(pp, PAYLOAD_SIZE(pp)))
/* Get next block payload pointer from pp (current payload pointer) */
#define NEXT_BLOCK(pp) (MOVE_BYTE(pp, BLOCK_SIZE(pp)))
/* Get previous block payload pointer from pp (current payload pointer) */
#define PREV_BLOCK(pp) (MOVE_BYTE(pp, - READ_SIZE(MOVE_WORD(pp, -2))))
/* Read the block size at the payload pp */
#define BLOCK_SIZE(pp) (READ_SIZE(HEADER(pp)))
/* Read the payload size at pp */
#define PAYLOAD_SIZE(pp) (BLOCK_SIZE(pp) - DSIZE)
/* Check if the block at the payload pp is free */
#define IS_FREE(pp) (!(READ_ALLOC(HEADER(pp))))
/* Sets the size and allocation-bit to header/footer of block at pp */
#define SET_INFO(pp, size, alloc)\
((WRITE(HEADER(pp),(size),(alloc))), \
(WRITE(FOOTER(pp),(size),(alloc))))
/* Sets the size to header/footer of block at pp */
#define SET_SIZE(pp, size)\
((WRITE_SIZE(HEADER(pp),(size))), \
(WRITE_SIZE(FOOTER(pp),(size))))
/* Sets the allocation-bit to header/footer of block at pp */
#define SET_ALLOC(pp, alloc)\
((WRITE_ALLOC(HEADER(pp),(alloc))), \
(WRITE_ALLOC(FOOTER(pp),(alloc))))
/* Get the predecessor payload address */
#define GET_PRED(pp) ((WTYPE *)(READ_WORD(pp)))
/* Get the successor payload address */
#define GET_SUCC(pp) ((WTYPE *)(READ_WORD(MOVE_WORD(pp, 1))))
/* Set the predecessor payload address to pred_pp */
#define SET_PRED(pp, pred_pp) (WRITE_WORD(pp, ((WTYPE) pred_pp)))
/* Set the successor payload address to succ_pp */
#define SET_SUCC(pp, succ_pp) (WRITE_WORD(MOVE_WORD(pp, 1), ((WTYPE) succ_pp)))
/* ======================= Private Global Variables ============================== */
// private global variable
static WTYPE** seglist; /* array of free-list pointers */
/* =========================== Public Functions ================================== */
/*
* Initialize the malloc package.
* return 0 on success, -1 on error.
*/
int mm_init(void) {
/* Create the initial empty heap */
void* heap = mem_sbrk((SEGLIST_NUM + 2) * WSIZE); /* seglist + head + tail */
if (heap == (void*)-1) return -1;
seglist = heap;
heap = MOVE_WORD(heap, SEGLIST_NUM);
// initialize the seglist
for(int i = 0; i < SEGLIST_NUM; ++i){
seglist[i] = NULL;
}
WRITE(heap, 0, 1); /* Head Word */
WRITE(MOVE_WORD(heap, 1), 0, 1); /* Tail Word */
/* Extend the empty heap with a small free block */
if (extend_heap(4 * MIN_BLOCK_SIZE) == NULL) return -1;
heap_check(__LINE__);
return 0;
}
/*
* Allocate an aligned block of memory of at least size bytes
* Return address of allocated block on success, NULL on error.
*/
void* mm_malloc(size_t size) {
if (size == 0) return NULL;
void* pp; /* Payload Pointer */
size = ALIGN(size + DSIZE); /* Add header and footer words */
size = MAX(size, MIN_BLOCK_SIZE);
/* Search the free list for a fit */
if ((pp = find_fit(size)) == NULL) {
/* No fit found, request a block from the memory */
if (size > CHUNKSIZE){
pp = extend_heap(size);
}else{
pp = extend_heap(4 * CHUNKSIZE);
chop_block(pp, size);
}
if (pp == NULL) return NULL;
}
pp = place(pp, size);
heap_check(__LINE__);
return pp;
}
/*
* Free the allocated block at ptr, and coalesce it.
*/
void mm_free(void* ptr) {
SET_ALLOC(ptr, 0);
link_block(ptr);
coalesce(ptr);
heap_check(__LINE__);
}
/*
* # ptr = NULL : allocate block of the given size.
* # size = 0 : free the given block, return NULL.
* # else: resize the allocated block at ptr.
*
* Return address of the reallocated block, NULL on error.
*/
void* mm_realloc(void* ptr, size_t size) {
if (ptr == NULL){
return mm_malloc(size);
}else if (size == 0){
mm_free(ptr);
return NULL;
}else{
ptr = resize_block(ptr, size);
heap_check(__LINE__);
return ptr;
}
}
/* =========================== Private Functions ================================== */
/*
* Resize the allocated block at pp to have size bytes
* Return address of the resized block, NULL on error.
*/
static void* resize_block(void* pp, size_t size) {
size_t asize = MAX(MIN_BLOCK_SIZE, ALIGN(size + DSIZE));
size_t bsize = BLOCK_SIZE(pp);
size_t csize = bsize - asize;
if (asize > bsize) {
if (can_expand(pp, asize)) return expand_block(pp, asize);
return reallocate_block(pp, size);
}
// Split only if the fragment is large enough.
if (csize >= (4 * MIN_BLOCK_SIZE)){
SET_INFO(pp, asize, 1);
void* fp = NEXT_BLOCK(pp);
SET_INFO(fp, csize, 0);
link_block(fp);
}
return pp;
}
/*
* Allocate block of the given size, copy content, free old block
* Return address of the new block, NULL on error.
*/
static void* reallocate_block(void* ptr, size_t size) {
void *newptr = mm_malloc(size);
if (newptr == NULL) return NULL;
size_t copy_size = MIN(PAYLOAD_SIZE(ptr), size);
memcpy(newptr, ptr, copy_size);
mm_free(ptr);
return newptr;
}
/**
* checks if the allocated-block at pp can expand to have the given size
*/
static int can_expand(void* pp, size_t size){
size_t bsize = BLOCK_SIZE(pp);
for(void* ptr = NEXT_BLOCK(pp); IS_FREE(ptr) ; ptr = NEXT_BLOCK(ptr)){
bsize += BLOCK_SIZE(ptr);
if (bsize >= size) return 1;
}
for(void* ptr = pp; !READ_ALLOC(MOVE_WORD(ptr, -2)) ; ){
ptr = PREV_BLOCK(ptr);
bsize += BLOCK_SIZE(ptr);
if (bsize >= size) return 1;
}
return 0;
}
/**
* expands the allocated-block at pp until it has the given size
* return address to the new expanded block
*/
static void* expand_block(void *pp, size_t size) {
void* cpp = pp;
size_t bsize = BLOCK_SIZE(pp);
for(void* ptr = NEXT_BLOCK(pp); IS_FREE(ptr) ; ptr = NEXT_BLOCK(ptr)){
bsize += BLOCK_SIZE(ptr);
unlink_block(ptr);
if (bsize >= size) break;
}
if (bsize >= size) {
SET_INFO(cpp, bsize, 1);
return cpp;
}
for(void* ptr = pp; !READ_ALLOC(MOVE_WORD(ptr, -2)) ; ){
cpp = ptr = PREV_BLOCK(ptr);
bsize += BLOCK_SIZE(ptr);
unlink_block(ptr);
if (bsize >= size) break;
}
if (cpp != pp) memmove(cpp, pp, PAYLOAD_SIZE(pp));
SET_INFO(cpp, bsize, 1);
return cpp;
}
/**
* chop the given free-block into a small free-blocks of the given size.
*/
static void chop_block(void* pp, size_t size){
if ((pp == NULL) || (size < MIN_BLOCK_SIZE)) return;
size_t bsize = BLOCK_SIZE(pp);
if ((size + MIN_BLOCK_SIZE) > bsize) return;
unlink_block(pp);
while(bsize >= (size + MIN_BLOCK_SIZE)){
SET_INFO(pp, size, 0);
link_block(pp);
pp = NEXT_BLOCK(pp);
bsize -= size;
}
SET_INFO(pp, bsize, 0);
link_block(pp);
}
/**
* Add free block with aligned size to the end of the heap.
* Return address of the added free block, NULL on error.
*/
void* extend_heap(size_t size) {
WTYPE* pp;
size = ALIGN(size);
if ((long)(pp = mem_sbrk(size)) == -1) return NULL;
SET_INFO(pp, size, 0); /* Initialize a free block */
link_block(pp);
WRITE(HEADER(NEXT_BLOCK(pp)), 0, 1); /* New Tail Word */
return pp;
}
/* Find the first block greater than or equal to size
* Return address of the first-fit, NULL if no-fit.
*/
static void* first_fit(void* free_list, size_t size) {
for (void* pp = free_list; pp != NULL ; pp = GET_SUCC(pp)) {
if (size <= BLOCK_SIZE(pp)) return pp;
}
return NULL;
}
/* Find the smallest block greater than or equal to size
* Return address of the best-fit, NULL if no-fit.
*/
static void* best_fit(void* free_list, size_t size) {
void* pp;
void* best = NULL;
size_t best_size = __SIZE_MAX__;
for (pp = free_list; pp != NULL ; pp = GET_SUCC(pp)) {
size_t curr_size = BLOCK_SIZE(pp);
if ((size <= curr_size) && (curr_size < best_size)){
best = pp;
}
}
return best;
}
/**
* Find a free block with size greater than or equal to size.
* Return address of a fit-block, NULL if no fit.
*/
static void* find_fit(size_t size) {
for(int i = seg_index(size); i < SEGLIST_NUM; ++i){
void* fit = best_fit(seglist[i], size);
if (fit != NULL) return fit;
}
return NULL;
}
/**
* Allocate the free block at pp.
* Split the block if the remainder is greater than MIN_BLOCK_SIZE.
* Returns the address of the allocated block payload
*/
static void* place(void *pp, size_t size) {
size_t bsize = BLOCK_SIZE(pp);
size_t csize = bsize - size;
unlink_block(pp);
if (csize < MIN_BLOCK_SIZE){
SET_ALLOC(pp, 1);
}else{
SET_INFO(pp, csize, 0);
link_block(pp);
pp = NEXT_BLOCK(pp);
SET_INFO(pp, size, 1);
}
return pp;
}
/**
* Coalesce the current block with its free previous and/or next blocks.
* Return the address of the coalesced block.
*/
static void* coalesce(void *pp) {
void* cpp = pp; /* coalesced payload pointer */
void* prev_footer = MOVE_WORD(pp, -2);
void* next_header = HEADER(NEXT_BLOCK(pp));
size_t prev_alloc = READ_ALLOC(prev_footer);
size_t next_alloc = READ_ALLOC(next_header);
size_t curr_alloc = !IS_FREE(pp);
size_t size = BLOCK_SIZE(pp);
if (prev_alloc && next_alloc) return pp;
if (!curr_alloc) unlink_block(pp);
if (!next_alloc) {
size += READ_SIZE(next_header);
unlink_block(MOVE_WORD(next_header, 1));
}
if (!prev_alloc) {
size += READ_SIZE(prev_footer);
cpp = PREV_BLOCK(pp);
unlink_block(cpp);
if (curr_alloc) memmove(cpp, pp, PAYLOAD_SIZE(pp));
}
SET_INFO(cpp, size, curr_alloc);
if (!curr_alloc) link_block(cpp);
return cpp;
}
/**
* Add the block at pp to the free-list
*/
static void link_block(void* pp){
int index = seg_index(BLOCK_SIZE(pp));
WTYPE* list = seglist[index];
if (list) SET_PRED(list, pp);
SET_SUCC(pp, list);
SET_PRED(pp, NULL);
seglist[index] = pp;
}
/**
* Remove the block at pp from the free-list
*/
static void unlink_block(void* pp) {
int index = seg_index(BLOCK_SIZE(pp));
WTYPE* pred_pp = GET_PRED(pp);
WTYPE* succ_pp = GET_SUCC(pp);
if (pred_pp) SET_SUCC(pred_pp, succ_pp);
if (succ_pp) SET_PRED(succ_pp, pred_pp);
if (pp == seglist[index]) seglist[index] = succ_pp;
}
/**
* Returns the index of the seglist that should contain blocks of the given size
*/
static int seg_index(size_t size){
if (size <= MIN_BLOCK_SIZE) return 0;
if (size <= (2 * MIN_BLOCK_SIZE)) return 1;
if (size <= (4 * MIN_BLOCK_SIZE)) return 2;
if (size <= (8 * MIN_BLOCK_SIZE)) return 3;
if (size <= (16 * MIN_BLOCK_SIZE)) return 4;
if (size <= (64 * MIN_BLOCK_SIZE)) return 5;
if (size <= (256 * MIN_BLOCK_SIZE)) return 6;
return 7;
}
/* ========================== Debugging Functions =============================== */
#ifdef DEBUG
/**
* Heap Consistency Checker, checks for:
* - head and tail words of the heap
* - block header and footer equality
* - block size >= minimum size
* - payload alignment
* - coalescing (no contiguous free blocks)
* - total heap size
* - seglist consistency.
*/
static void mm_check(int line){
WTYPE* ptr = MOVE_WORD(mem_heap_lo(), SEGLIST_NUM);
WTYPE* end_ptr = MOVE_BYTE(ptr, mem_heapsize()) - (SEGLIST_NUM + 1);
// Check head word (size = 0, allocated)
if (READ_SIZE(ptr) != 0){
printf("Error at %d: head-word size = %u\n",line, READ_SIZE(ptr));
}
if (READ_ALLOC(ptr) != 1){
printf("Error at %d: head-word is not allocated\n",line);
}
// Check tail word (size = 0, allocated)
if (READ_SIZE(end_ptr) != 0){
printf("Error at %d: tail-word size = %u\n",line, READ_SIZE(end_ptr));
}
if (READ_ALLOC(end_ptr) != 1){
printf("Error at %d: tail-word is not allocated\n",line);
}
size_t heap_size = (SEGLIST_NUM + 2) * WSIZE;
int free_count = 0;
int prev_free = 0;
// Check regular blocks
for (ptr = MOVE_WORD(ptr, 2); ptr < end_ptr; ptr = NEXT_BLOCK(ptr)){
// check header and footer equality
if (READ_WORD(HEADER(ptr)) != READ_WORD(FOOTER(ptr))){
printf("Error at %d: at block %p => header = %u, footer = %u\n",
line, ptr, READ_WORD(HEADER(ptr)), READ_WORD(FOOTER(ptr)));
}
// check that block size >= minimum size
if (BLOCK_SIZE(ptr) < MIN_BLOCK_SIZE){
printf("Error at %d: block %p has size < min size, (%u < %u)\n",
line, ptr, BLOCK_SIZE(ptr), MIN_BLOCK_SIZE);
}
// check payload alignment
if((unsigned) ptr % ALIGNMENT){
printf("Error at %d: block %p is not aligned to %d\n",
line, ptr, ALIGNMENT);
}
// check coalescing.
if (prev_free && IS_FREE(ptr)){
printf("NOTE at %d: two contiguous free blocks not coalesced\n", line);
}
if(IS_FREE(ptr)) ++free_count;
prev_free = IS_FREE(ptr);
heap_size += BLOCK_SIZE(ptr);
}
// check total heap size
if (heap_size != mem_heapsize()){
printf("Error at %d: heap size not accurate, %u should be %u\n",
line, heap_size, mem_heapsize());
}
// check seglist consistency
check_seglist(line, free_count);
}
/**
* Seglist Consistency Checker, checks for:
* - seglist pointer
* - each free-list consistency
* - the free-block count in seglist matches the free_count (free-blocks in the heap)
*/
static void check_seglist(int line, int free_count){
int count = 0;
// checks the seglist pointer
if (seglist != mem_heap_lo()){
printf("Error at %d: Seglist pointer doesn't point to heap start address.\n",
line);
}
// check each free-list in the seglist
for(int i = 0; i < SEGLIST_NUM; ++i){
count += check_free_list(line, i);
}
// check the free-block count in seglist matches the free_count
if (count != free_count){
printf("Error at %d: %d missing free-blocks from the seglist.\n",
line, (free_count - count));
}
}
/**
* Free-List Consistency Checker, checks for:
* - blocks are free.
* - free-blocks are in heap range.
* - the predecessor consistency.
* Return the number of blocks in the free-list
*/
static int check_free_list(int line, int li){
void* start_ptr = MOVE_WORD(mem_heap_lo(), SEGLIST_NUM);
void* end_ptr = MOVE_BYTE(start_ptr, mem_heapsize()) - (SEGLIST_NUM + 1);
void* pred_pp = NULL;
int count = 0;
for(void* pp = seglist[li]; pp != NULL; pp = GET_SUCC(pp)){
// check if block is free
if (!IS_FREE(pp)){
printf("Error at %d: Seglist[%d] contains an allocated-block %p.\n",
line, li, pp);
}
// check if free-block in heap range
if (pp <= start_ptr || pp >= end_ptr){
printf("Error at %d: Seglist[%d] contains a free-block %p out of the heap range.\n",
line, li, pp);
}
// check the predecessor pointer
if (pred_pp != GET_PRED(pp)){
printf("Error at %d: in Seglist[%d], inconsistant predecessor link at %p.\n",
line, li, pp );
}
++count;
pred_pp = pp;
}
return count;
}
#endif
๐ค ์คํ, ์์ ํด์ผํ ๋ด์ฉ์ ๋๊ธ๋ก ๋ถํ๋๋ฆฝ๋๋ค. ๊ณต๋ถ ์ค์ธ ๋ด์ฉ์ ์ ๋ฆฌํ์ฌ ์ฌ๋ฆฐ ๊ฒ์ด๋ฏ๋ก ํ๋ฆฐ ๋ด์ฉ์ ๊ดํด์ ์ฝ๋ฉํธ ๋ฐ ์ง๋ฌธ ํ์ํฉ๋๋ค.