[Malloc_Lab] 묵시적 가용 리스트를 이용한 동적 메모리 할당기 (4)

Laska·2025년 4월 28일
post-thumbnail

묵시적 할당기로 만든 함수에 대해 알아보자...
레츠고...

place

빈 블록(bp)에 asize 만큼의 메모리를 할당해주는 함수이다.

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

코드 흐름 요약

  1. 현재 블록 (bp) 의 크기를 가져와서 csize에 저장한다.

  2. 만약 현재 블록 크기 - 요청 크기가 16바이트 이상 남게 된다면,
    (`2*DSIZE로 16바이트 = 헤더 + 푸터 공간 포함 새 블록을 만들 최소 크기를 만든다.)

  3. 먼저, 앞부분 (asize 크기만큼)을 할당한 블록으로 만든다.
    (헤더 와 푸터에 asize 크기와 alloc = 1 표시)

  4. 그리고 bp를 남은 블록의 시작으로 이동시킨다.

  5. 남은 부분을 새로운 빈 블록(free block)으로 만든다.
    (헤더/푸터에 남은 크기, alloc = 0 기록)

위 조건이 만족 하지 않는다면

빈 블록 전체를 그냥 통쨰로 할당해버린다.
(남은 공간이 너무 작아서 나누는 것이 의미가 없을 때)

먼가 통째로 준다는게... 그냥 에라잇 다 가져가라 ~ 느낌이라 재밌었다.


mm_malloc

드디어... 드디어 말록이다 !!!

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_malloc(size) 여기서 size만큼 메모리를 할당하는 메인 할당 함수이다. 실제로 malloc처럼 행동하는 친구이다.


간단한 동작 예시는 다음과 같다.
  1. 요청한 크기(size)를 기준으로, 실제로 필요한 크기 asize를 계산한다.
  2. 빈 블록을 찾아서 있으면 바로 거기에 할당한다.
  3. 없으면 힙을 확장하여 메모리를 만들고 할당해준다.

간단하다. 그러니까 이제 코드 뜯어보자.


최소블록 맞추기

if (size <= DSIZE)
    asize = 2 * DSIZE;
else
    asize = DSIZE * ((size + (DSIZE) + (DSIZE -1)) / DSIZE);

만약 요청 크기가8바이트(DSIZE) 이하면, 최소 블록 크기인 16바이트(2xDSIZE)로 강제한다.

이유는 ? 헤더와 푸터를 사용한다면 최소한 이정도는 있어야하니까...

그 외는 먼저 size와 헤더 공간에 더한 후에 8바이트 단위로 반올림 하여, 8의 배수를 맞춰준다 !



비슷한 녀석 찾기

if ((bp = find_fit(asize)) != NULL) {
    place(bp, asize);
    return bp;
}

extendsize = MAX(asize, CHUNKSIZE);
if ((bp = extend_heap(extendsize / WSIZE)) == NULL)
    return NULL;

find_fit을 통해 크기에 맞는 빈 블록을 찾고, 찾았으면 place함수를 이용하여 할당 후 리턴 !

=> 여기서 find_fit알고리즘 들은 다음 포스트에서 다룰 것이다.


만약 빈 블록이 없다면

extendsize함수를 사용하여 요청한 크기와 CHUNKSIZE중 더 큰 걸 선택한다.
(힙을 확장 할 때 너무 작게 늘리면 비효율 적이므로 최소한의 CHUNKSIZE 단위로 늘린다.

후에 힙을 늘리고 늘린 영역의 bp를 받는다.



마무리

place(bp, asize);
return bp;

-> 힙 확장에 성공했다면, 늘린 곳에 요청한 만큼 place함수로 할당 해준 후에 포인터를 리턴 !

전체 흐름은 이렇게 된다.

size 요청
    ↓
size 0? → NULL 리턴
    ↓
asize 계산 (8의 배수로)
    ↓
find_fit(asize)
    ├─ 찾음 → place(bp, asize) → bp 리턴
    └─ 못찾음
          ↓
   extend_heap(최소 CHUNKSIZE)
          ↓
   place(bp, asize)
          ↓
   bp 리턴



REALLOC

말그대로 다시 할당이다.

기존에 할당된 메모리 oldptr을 새 크기(size) 만큼 다시 할당해주고,
내용을 복사 한 후에 기존 메모리를 해제하는 함수이다.

temp를 통해 값을 담고 교환하는 알고리즘과 묘하게 닮아있다.

void *oldptr = ptr;
    void *newptr;
    size_t copySize;

    newptr = mm_malloc(size);
    if (newptr == NULL)
        return NULL;
    copySize = *(size_t *)((char *)oldptr - SIZE_T_SIZE);
    if (size < copySize)
        copySize = size;
    memcpy(newptr, oldptr, copySize);
    mm_free(oldptr);
    return newptr;

해당 함수의 흐름을 정리하면

  1. 새 메모리 확보 (newptr = mm_malloc(size))
  2. oldptr의 크기를 가져옴 (헤더에서 읽기)
  3. 작은 쪽 크기만큼 복사 (memcpy)
  4. 옛날 메모리 해제 (mm_free)
  5. 새 포인터 리턴

위 순서로 진행된다. 이건 따로 정리를 안하려고 한다.



FREE

메모리 할당을 해제하는 함수이다. 이전 포스트에서 나왔던 COALESCE 함수가 여기서 쓰인다.

void mm_free(void *ptr)
{
    size_t size = GET_SIZE(HDRP(ptr));

    PUT(HDRP(ptr), PACK(size, 0));
    PUT(FTRP(ptr), PACK(size, 0));
    coalesce(ptr);
}

동작 과정 또한 간단하다.

헤더, 푸터 상태를 할당 해제로 바꾸고, 합칠 만한 친구가 있는지 CASE를 살펴본다.



모든 함수들을 하나씩 씹어봤다... 다음은 드디어 묵시적 가용 리스트에서 할 수 있는
모든 fit 들을 구현해 볼 예정이다... 파이팅..

profile
똑똑해지고 싶어요

0개의 댓글