이전 글에서 메모리는 단순한 저장 공간이 아니라
운영체제와 하드웨어가 함께 관리하는 구조라고 정리했다.
그럼 여기서 자연스럽게 다음 질문이 나온다.
“그럼 malloc은 도대체 어디서 메모리를 가져오는 걸까?”
코드를 보면 너무 단순하다.
void *p = malloc(100);
이 한 줄로 메모리를 받는다.
그래서 처음에는 이렇게 생각하기 쉽다.
“malloc이 운영체제에서 바로 100바이트를 가져오겠지”
그런데 실제로는 대부분 그렇지 않다.
malloc은 생각보다 “게으르게” 동작한다
핵심부터 보면 이렇다.
malloc은 요청이 올 때마다 OS에 가지 않는다
이게 꽤 중요한 포인트다.
우리가 직관적으로 생각하는 흐름
malloc → OS 요청 → 메모리 반환
실제 흐름
malloc → 이미 있는 메모리에서 찾기 → 없으면 OS 요청
즉, malloc은 “메모리를 만들어내는 함수”가 아니라
이미 확보해둔 메모리를 나눠 쓰는 관리자다.
그럼 처음 메모리는 어디서 오냐
결국 한 번은 OS에서 받아와야 한다.
이때 사용하는 방법이 두 가지다.
- sbrk
- mmap
sbrk — 힙을 늘리는 방식
먼저 전통적인 방법이다.
프로세스의 힙(heap)을 뒤로 밀어서 메모리를 확보한다
그림으로 보면
기존 힙
[--------]
sbrk 호출
확장된 힙
[------------]
이 방식은 굉장히 단순하다.
- 그냥 끝을 늘린다
- 연속된 메모리를 얻는다
문제는 명확하다
- 중간에 있는 메모리는 OS에 돌려주기 어렵다
- 계속 쌓이기만 한다
그래서 fragmentation 문제가 생기기 쉽다.
mmap — 새로운 영역을 따로 만든다
그래서 등장한 방식이 mmap이다.
기존 힙과는 별도로, 새로운 메모리 영역을 만든다
개념적으로 보면
힙
[--------]
mmap 영역
[------]
이 방식은 훨씬 유연하다.
- 필요할 때만 만든다
- 필요 없어지면 바로 반환 가능하다
그래서 큰 메모리를 처리할 때는 mmap이 훨씬 유리하다.
malloc은 둘 중 하나를 선택한다
여기서 중요한 포인트가 하나 있다.
malloc은 상황에 따라 sbrk와 mmap을 선택한다
대략적으로 보면:
- 작은 메모리 → 기존 힙에서 처리 (sbrk 기반)
- 큰 메모리 → mmap
왜 이렇게 나눌까?
작은 요청까지 mmap을 쓰면
시스템 콜이 너무 많이 발생해서 느려진다.
반대로 큰 메모리를 힙에서 관리하면
반환도 어렵고 단편화도 심해진다.
👉 그래서 둘을 섞어서 쓴다.
malloc의 진짜 전략
여기서 중요한 포인트 하나 더 있다.
malloc은 최대한 OS를 안 부르려고 한다
그래서 실제 동작은 이렇게 된다.
1. OS에서 큰 덩어리 확보
2. 내부에서 잘게 나눔
3. free되면 다시 재사용
즉,
“한 번 받아서 계속 돌려쓴다”
그래서 free해도 메모리가 안 줄어든다
이 구조 때문에 처음 보면 이상한 현상이 생긴다.
free(p);
했는데도:
- 메모리가 줄어들지 않음
- RSS 그대로
이유는 단순하다.
free는 OS에 반환하는 게 아니라
malloc 내부로 되돌리는 것뿐이다
즉:
free
↓
메모리 OS 반환 X
↓
allocator 내부 저장
그래서 다음 malloc이 빠르다.
그럼 언제 OS로 돌아가나
완전히 안 돌려주는 건 아니다.
mmap으로 받은 경우
free → munmap → OS 반환
힙(sbrk)인 경우
- 힙의 끝 부분이어야 함
- 조건이 까다로움
그래서 대부분의 경우:
프로세스가 메모리를 계속 들고 있게 된다
정리하면 흐름은 이렇다
malloc 요청
↓
내부에서 찾기
↓
없으면
↓
sbrk 또는 mmap
여기까지 이해하면 보이는 것들
이 구조를 이해하면 다음이 자연스럽게 설명된다.
malloc이 빠른 이유
→ 대부분 재사용이기 때문
free해도 메모리가 안 줄어드는 이유
→ OS에 반환하는 게 아니기 때문
mmap이 중요한 이유
→ 큰 메모리는 따로 관리해야 하기 때문
다음 글로 이어지는 질문
여기까지 보면 자연스럽게 이런 질문이 나온다.
“그럼 malloc 내부에서는 어떻게 나눠서 관리할까?”
이게 다음 글 내용이다.
'프로그래밍공부(Programming Study) > CS-운영체제(OS)' 카테고리의 다른 글
| O(1)인데 왜 느려질까 (메모리 성능의 진짜 문제) (0) | 2026.04.03 |
|---|---|
| malloc은 내부에서 어떻게 메모리를 관리할까 (1) | 2026.04.02 |
| 메모리는 그냥 “값을 넣는 공간”이 아니다 (0) | 2026.03.31 |
| 현대 고성능 서버의 데이터 전송 메커니즘: epoll부터 TCP BBR까지 (0) | 2026.01.18 |
| OSTEP: 10. Multiprocessor Scheduling (Advanced) (0) | 2025.10.10 |
댓글