메모리에 쓸 수 없는 빈틈이 생기는 현상. 두 종류가 있다.
-
내부 단편화 — 할당 '단위 안' 에 남는 빈틈
- 4KB 페이지에 100바이트만 쓰면 3,996바이트가 논다
- 고정 크기 할당(페이징) 에서 발생
-
외부 단편화 — 할당 '사이' 에 남는 빈틈
- [사용][빈 3KB][사용][빈 2KB][사용]
- 총 5KB 가 비어 있어도 4KB 를 연속으로 못 준다
- 가변 크기 할당(세그멘테이션) 에서 발생
페이징이 외부 단편화를 없앤다
모든 블록이 같은 크기이므로 '들어갈 자리가 없는' 일이 생기지 않는다 비어 있는 프레임이면 어디든 쓸 수 있다
대가로 내부 단편화가 생기지만, 평균 페이지의 절반(2KB) 수준이라 감당된다
페이지 크기의 트레이드오프
-
크게 하면 — 페이지 테이블이 작아지고 TLB 적중률이 오른다
- 내부 단편화가 커지고, 폴트 시 읽는 양이 는다
-
작게 하면 — 내부 단편화가 줄지만
- 페이지 테이블이 커지고 폴트가 잦아진다
일반 4KB, 대용량 워크로드는 2MB·1GB huge page 를 쓴다 (DB·JVM 이 huge page 로 TLB 미스를 줄이는 것이 대표적)
디스크에도 있다
파일 시스템의 조각화도 같은 개념이다 파일이 흩어져 저장되면 순차 읽기가 랜덤 접근이 된다
- HDD 에서 심각했고, SSD 에서는 영향이 훨씬 작다
컴팩션 — 외부 단편화의 정면 대응
흩어진 사용 영역을 한쪽으로 몰아 빈 공간을 합친다
비용이 크다 — 데이터를 실제로 옮겨야 하고,
- 옮기는 동안 해당 영역을 못 쓴다
GC 에서 같은 개념이 등장한다
마크-스윕 단편화가 남는다 (빠르지만 빈틈 발생)
마크-컴팩트 정리하지만 이동 비용
복사(copying) 살아남은 것만 다른 영역에 옮겨 붙인다 — 단편화 0
메모리 할당자의 대응
-
슬랩 할당자 — 같은 크기의 객체를 모아 두는 캐시를 만든다
- 커널이 inode · task_struct 같은 고정 크기 객체에 사용
- 외부 단편화 억제 + 초기화 비용 절감
-
버디 시스템 — 2의 거듭제곱 크기로만 나누고 합친다
- 합병이 O(log n) 으로 빠르다. 내부 단편화는 최대 50%
장기 실행 서버의 증상
RSS 는 늘어나는데 실제 사용량은 그대로 → 할당자 단편화 의심
- 크기가 제각각인 할당·해제가 오래 반복될 때
- glibc malloc 은 반환된 메모리를 OS 에 잘 안 돌려준다
- jemalloc · tcmalloc 으로 교체하면 개선되는 경우가 많다
면접 함정
- ❌ "페이징은 단편화가 없다" → 외부 단편화가 없을 뿐 내부는 있다.
- ❌ "페이지를 크게 하면 무조건 빠르다" → 내부 단편화와 폴트 비용이 는다.