각 메모리 블록은 다음과 같은 구조를 가짐:
#define WSIZE 4 /* 워드 크기 (바이트) */
#define DSIZE 8 /* 더블 워드 크기 (바이트) */
#define CHUNKSIZE (1<<12) /* 힙 확장 크기 (4KB) */
// 블록 크기와 할당 상태를 하나의 워드로 패킹
#define PACK(size, alloc) ((size) | (alloc))
// 포인터 p가 가리키는 주소에서 4바이트 워드를 읽고 쓰기
#define GET(p) (*(unsigned int *)(p))
#define PUT(p, val) (*(unsigned int *)(p) = (val))
// 헤더/푸터에서 정보 추출
#define GET_SIZE(p) (GET(p) & ~0x7) // 블록 크기
#define GET_ALLOC(p) (GET(p) & 0x1) // 할당 상태
// 블록 포인터 계산
#define HDRP(bp) ((char *)(bp) - WSIZE)
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)
// 인접한 블록의 주소 계산
#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) // bp에 현재 블록의 크기를 더해 다음 블록의 bp를 계산
#define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) // bp에서 이전 블록의 크기를 빼서 이전 블록의 bp를 계산


힙을 초기화하고 초기 구조를 설정:

int mm_init(void)
{
// 16바이트로 초기 힙 구조 생성
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;
}
First-fit 알고리즘을 사용하여 적합한 가용 블록을 찾아 할당:
void *mm_malloc(size_t size)
{
size_t asize; /* 조정된 블록 크기 */
size_t extendsize; /* 확장할 크기 */
char *bp;
if (size == 0)
return NULL;
// 블록 크기 조정 (최소 16바이트)
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;
}
블록을 해제하고 인접한 가용 블록들과 병합:
void mm_free(void *ptr)
{
if (ptr == NULL)
return;
size_t size = GET_SIZE(HDRP(ptr));
// 블록을 가용 상태로 변경
PUT(HDRP(ptr), PACK(size, 0));
PUT(FTRP(ptr), PACK(size, 0));
// 인접 블록들과 병합
coalesce(ptr);
}
인접한 가용 블록들을 병합하여 외부 단편화를 줄이기:

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

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;
}
남은 공간이 충분하면 블록을 분할하여 내부 단편화 줄이기:

static void place(void *bp, size_t asize) {
size_t csize = GET_SIZE(HDRP(bp));
// 남은 공간이 최소 블록 크기(16바이트) 이상이면 분할
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));
}
}