큰 메모리를 시스템으로부터 얻어오는 것으로 시작.
리눅스의 경우 brk/sbrk 가 메모리 할당.
sbrk : space break 함수로, 힙 크기를 늘이거나 줄이는 함수다. 커널의 brk 포인터(힙의 맨 끝을 가리키는 포인터)에 incr만큼 크기를 더해서 힙을 늘이거나 줄인다. 성공하면 이전의 brk 포인터 값을 리턴한다. 실패하면 -1을 리턴하고 errno = ENOMEM 이라고 설정해준다. incr = 0이면 늘어나지 않았으니 현재의 brk 값을 리턴한다.
sbrk는 페이지 단위로 할당(4KB) → 사이즈가 큰 편이라 이걸 잘게 썰어주고 관리하는 게 heap management library.
free node는 segregated free list에서 free node 리스트별로 관리. ⇒ 상수 시간에 요청 완료.
free node 크기가 512바이트보다 작은 경우 그 크기별로 모두 관리되는데, 링크드 리스트 형태로 관리.
16바이트짜리 free node 리스트, 24 바이트짜리 노드 리스트 등.
그래서 상수 시간에 완료되는 것!
각 크기에 대한 리스트를 하나 또 따로 들고 있음. 이 리스트에는 각 크기가 적혀 있어서 해당 크기의 링크드 리스트로 연결해줌.
malloc()의 할당 단위는 최소 8바이트(위의 페이지 할당 단위(4096 바이트)와 비교하면 매우 큰 차이)
malloc(14), malloc(15) 8바이트에 맞춰서 align해줘야 하니 패딩과 헤더/footer 등을 포함해서 총 24바이트가 할당!
free를 할 때는 coalescing(병합)과정을 통해 인접한 free 노드를 합쳐서 하나의 큰 free 노드를 만든다.
매핑할 메모리의 위치와 크기를 인자로 받는다.
메모리에 매핑된 데이터는 파일 입출력 함수를 사용하지 않고 직접 읽고 쓸수 있다는 장점이 있다.
mmap()에서는 할당 메모리의 크기가 최소 4KB(mmap()은 페이지 크기의 배수로 할당).
mmap은 “가상 메모리”에 매핑하는 함수. 할당해야 할 메모리 크기가 크면 mmap()으로 할당. mmap()에서는 페이지 단위(최소 4KB - 4096 Bytes)로 영역을 할당해주는 반면, 그 이하는 malloc()으로 heap에서 할당.
mmap을 사용하면 시스템 콜을 호출할 필요가 없다.
malloc의 경우 파일 입출력 함수를 쓰는데, open() 함수를 써서 파일 디스크립터를 받고 파일 오프셋을 이동시킨 다음 read 함수를 호출해서 데이터를 버퍼로 읽어와서 작업한다. 반면 mmap()을 쓰면 메모리에 매핑하고 나머지 작업은 해당 mmap에서 반환하는 주소가 가리키는 메모리 영역의 데이터를 대상으로 작업하기 때문에 매번 read 함수로 읽어올 필요가 없다.
malloc()은 free()를 호출한다고 해서 해당 메모리 자원이 시스템에 바로 반환되지 X(초기화 안됨.) 반면 munmap()의 경우에는 즉시 시스템에 반환됨.
malloc()은 큰 메모리 블록 요청이 들어오면 내부적으로 mmap()을 써서 메모리를 할당한다. 이때 큰 메모리 기준은 mallopt() 함수로 제어. 따라서 특별한 제어가 필요한 게 아니면 개발자가 직접 mmap()을 쓸 필요는 없음.
mmap()이 malloc()을 포함하는 개념이라기보다 mmap()은 시스템에서 제공하는 저수준 시스템 콜이며 특별한 조건일 때 메모리를 할당하는 효과를 볼 수 있다. malloc()은 메모리를 할당하는 C library 함수이며 내부적으로 mmap(), brk() 등 시스템 콜을 써서 구현.
mmap()은 단순히 메모리를 할당하는 시스템 콜이 아니므로 mmap()으로 쓴 코드를 모두 malloc()으로 바꿀 수는 없음.
참고 링크1
참고 링크2(나중에 꼭 참고해서 정리하기! 구현 내용 들어있음)