#include <stdlib.h>
// 리턴값은 void* (void 포인터)
void * malloc(size_t size) :
returns : pointer to allocated block if OK, NULL on error
malloc 함수는 블록 내에 포함될 수 있는 어떤 종류의 데이터 객체에 대해서 적절히 정렬된 최소 size 바이트를 갖는 메모리 블록의 포인터를 리턴한다. 실제 구현에서 정렬은 코드가 32bit 모드 (gcc -m32) 또는 64비트 모드(기본설정)에서 동작하도록 컴파일되었는지 여부에 따라 다르다. 32비트 모드에서 malloc은 주소가 항상 8의 배수인 블록을 리턴한다. 64비트 모드에서 주소는 항상 16의 배수다.
만일 malloc이 문제를 만난다면 (프로그램이 가용한 가상메모리보다 더 큰 크기의 메모리 블록을 요청하는 경우) null을 리턴하고 errno를 설정한다.
errno = 0;
malloc(...);
if (errno != 0) {
// 에러 발생
}
malloc 같은 동적 메모리 할당기는 mmap과 munmap 함수를 사용해서 명시적으로 힙 메모리를 할당하거나 반환하며 또는 sbrk 함수를 사용할 수 있다.
#include <unistd.h>
void * sbrk(intptr_t incr);
Returns : old brk pointer on success, -1 on error
sbrk 함수는 커널의 brk 포인터에 incr을 더해서 힙을 늘리거나 줄인다. 성공한다면 이전의 brk 값을 리턴하고 아니면 -1을 리턴하고 errno를 ENOMEM으로 설정한다. 만일 incr이 0이면, sbrk는 현재의 brk 값을 리턴한다.
sbrk를 음수 incr로 호출하면 합법적이기는 하지만, 리턴값(이전의 brk 값)이 새로운 힙의 탑을 지나서 abs(incr)바이트를 가리키기 때문에 복잡해진다
free 함수는 힙 블록을 반환한다..
Sbrk는 프로세스의 힙 끝(brk)을 늘리거나 줄이는 방식
힙이 한 덩어리처럼 커짐
[ code | data | heap........ ]
↑
힙 끝을 늘림
mmap은
[ code | data | heap ] [ 새로 매핑된 영역 ]
즉 mmap은 꼭 기존 힙 끝에 붙지 않아도 된다.
필요한 별도 가상 메모리 영역을 직접 매핑 가능
단편화에는 두가지 종류가 있다. 내부 단편화, 외부 단편화
내부 단편화 : 할당된 블록이 데이터 자체보다 더 클 때 일어난다.
외부 단편화 : 할당 요청을 만족시킬 수 있는 메모리 공간이 전체적으로 공간을 모았을 때는 충분한 크기가 존재하지만, 이 요청을 처리할 수 있는 단일한 가용블록은 없는 경우에 발생한다.
묵시적 할당은 힙에 있는 모든 블록을 처음부터 끝까지 순차적으로 탐색하면서 가용 블록을 찾는 방식이다.
즉, 가용 블록들만 따로 연결해서 관리하지 않고, 전체 블록 리스트 안에서 “이 블록이 할당 상태인지, 가용 상태인지”를 헤더를 통해 확인한다.
명시적 할당은 가용 블록들만 따로 연결 리스트로 관리하는 방식이다.
즉, free block 내부에 prev, next 포인터를 두어서 가용 블록끼리만 연결한다.
그래서 블록을 찾을 때는 전체 힙을 다 보는 것이 아니라 free list만 순회하면 된다.
Seglist는 명시적 할당을 더 발전시킨 방식이다.
가용 블록을 하나의 리스트로 관리하는 것이 아니라,크기별로 여러 개의 free list를 나누어서 관리한다.
ex)
작은 블록 리스트
중간 블록 리스트
큰 블록 리스트
이런 식으로 크기 구간마다 따로 관리한다.