학습 목표
가상 메모리가 물리 RAM보다 큰 주소 공간·여러 프로세스를 어떻게 지원하는지 설명할 수 있다.
요구 페이징(demand paging) 에서 페이지를 접근 시점에 올리는 이유를 설명할 수 있다.
페이지 폴트 발생 조건과 OS 폴트 핸들러 처리 단계를 설명할 수 있다.
FIFO·Optimal·LRU·Clock 교체 알고리즘의 아이디어와 한계를 비교할 수 있다.
문제 상황
- 서버 RAM 16GB인데 Java heap
-Xmx32g— 어떻게 돌아가나?- 전부 RAM에 있지 않음, 스왑·요구 페이징
- 처음
malloc(1GB)했을 때 물리 메모리가 바로 1GB 안 늘어난다- lazy allocation, PTE valid=0
- 디스크 I/O가 갑자기 늘고 CPU는 idle에 가깝다
- 페이지 폴트 폭주·스래싱 직전 신호
OOMKilled— 커널이 프레임 부족을 더 이상 버티지 못함
페이징·TLB를 봤다. 이번엔 디스크까지 포함한 주소 공간 환상과 프레임이 모자랄 때다.
1. 가상 메모리 개념
각 프로세스는 자기만의 가상 주소 공간을 본다. 물리 RAM은 공유 풀이고, 일부 페이지는 스왑(swap) 영역(디스크)에 둔다.

| 구분 | 설명 |
|---|---|
| 가상 주소 공간 | 프로세스 관점 — 코드·힙·스택·mmap |
| 물리 프레임 | 실제 DRAM 조각 — 한정된 자원 |
| 스왑 공간 | 디스크에 둔 페이지 백업 — RAM보다 훨씬 클 수 있음 |
| PTE valid=0 | 페이지가 RAM에 없음 — 디스크에 있거나 아직 미할당 |
- 메모리 오버커밋: 가상 합이 물리+스왑을 넘을 수 있음 — 실제 접근 시 OOM
- 격리: 프로세스 A의 가상 주소 0x1000과 B의 0x1000은 다른 물리 프레임
- 공유: 같은 물리 프레임을 여러 PTE가 가리킬 수 있음 (코드,
shm)
2. 요구 페이징 (Demand Paging)
미리 프로세스 전체를 RAM에 올리지 않는다. 참조할 때 페이지를 읽어 온다.
| 단계 | 동작 |
|---|---|
exec / fork |
페이지 테이블·mmap만 준비, 많은 PTE는 valid=0 |
| 첫 접근 | 페이지 폴트 → 디스크에서 프레임으로 로드 |
| 이후 접근 | PTE valid=1, 일반 페이징 |
- 순수 요구 페이징: swap 없이 처음 로드만 (실행 파일 backing store)
- 스왑 포함: RAM에서 내쳤다가 다시 접근하면 디스크에서 재로드
malloc대용량: 예약만 하고 physical page는 touch할 때 할당 (OS·런타임마다 다름)- COW(copy-on-write):
fork직후 쓰기 전까지 부모 프레임 공유 — 쓰기 시 폴트로 복사
3. 페이지 폴트 (Page Fault)
CPU가 논리 주소에 접근했는데 PTE가 valid=0 이거나 보호 위반이면 페이지 폴트 트랩이 난다.

일반적인 폴트 처리 (major fault):
- 하드웨어: MMU가 폴트 → CPU가 커널 모드로 전환, 폴트 주소·원인 저장
- OS 핸들러: 폴트가 합법적인지 확인 (스택 확장, COW, lazy alloc 등)
- 프레임 확보: 빈 프레임이 없으면 교체 알고리즘으로 victim 선택
- 디스크 I/O: 스왑 또는 파일에서 페이지 읽기 (major fault — 느림)
- PTE 갱신: frame#, valid=1, protection 설정
- 재실행: fault 난 명령부터 다시 — 이번엔 TLB miss 후 정상 접근
| 폴트 종류 | 예 |
|---|---|
| minor | 이미 RAM에 있는데 TLB만 비어 있음 |
| major | 디스크에서 페이지 읽어야 함 |
| illegal | NULL·권한 위반 → SIGSEGV |
minflt/majflt(time -v,/proc/[pid]/stat)로 관측- double page fault 등 재진입 케이스는 핸들러가 프레임·스택을 미리 확보해야 함
4. 페이지 교체 알고리즘
물리 프레임이 꽉 찼을 때 victim 페이지를 골라 RAM에서 내치고(스왑 또는 버림), 새 페이지를 올린다.
| 알고리즘 | 아이디어 | 장점 | 한계 |
|---|---|---|---|
| FIFO | 가장 먼저 들어온 프레임 교체 | 구현 단순(큐) | Belady: 프레임 늘려도 폴트 증가 가능 |
| Optimal | 가장 먼지 안 쓸 페이지 교체 | 폴트 수 이론적 최소 | 미래 참조 알 수 없음 — 벤치마크용 |
| LRU | 가장 오래 안 쓴 페이지 교체 | 지역성 반영 | 정확 LRU는 비용 큼 → 근사 LRU |
| Clock | reference bit 원형 스캔 | LRU 근사, 구현 실용적 | 한 바퀴만으로는 불완전 |
예시 (프레임 3개, 참조 순서 1,2,3,4,1,2,5,1,2,3,4,5):
| 알고리즘 | 페이지 폴트 수 (대표값) |
|---|---|
| FIFO | 9 |
| LRU | 5 |
| Optimal | 5 |

- Clock: 손가락이 프레임을 돌며 reference bit=1이면 0으로 내리고, 0이면 victim
- Linux 등은 LRU 근사(active/inactive list, aging) + dirty 페이지는 쓰기 비용 고려
- working set·스래싱은 다음 편에서
5. 스왑과 성능
| 항목 | 설명 |
|---|---|
| 스왑 아웃 | victim 페이지를 디스크에 쓰고 PTE valid=0 |
| 스왑 인 | 폴트 시 디스크에서 프레임으로 읽기 |
| thrashing | 폴트만 반복, 유용한 작업 거의 없음 — working set > RAM |
| swappiness | Linux가 얼마나 공격적으로 파일 캐시 대신 스왑 쓸지 (0~100) |
- SSD 스왑은 HDD보다 낫지만 RAM 접근 대비 여전히 느림
- 컨테이너·DB는 스왑 끄기도 흔함 — 지연 예측 가능성
- OOM killer: 스왑으로도 못 버티면 프로세스 강제 종료
6. 정리
- 가상 메모리 = 큰 가상 공간 + 제한된 프레임 + 스왑
- 요구 페이징으로 필요한 페이지만 로드, 페이지 폴트가 로드·교체 트리거
- 교체는 FIFO·LRU·Clock 등 — 실무는 LRU 근사 + dirty/reference 고려
- 다음: 세그멘테이션, working set, 스래싱 완화
다음에 다룰 것
- 세그멘테이션과 군집화
- working set, 스래싱
해당 내용은 Operating System Concepts, 10/E (Avraham Silberschatz, Peter Baer Galvin, Greg Gagne) 의 내용을 기반으로 합니다.