페이지 폴트
프로세스가 접근하려는 가상 메모리 페이지가 물리 메모리에 존재하지 않을 때 발생하는 Fault 유형의 예외(벡터 14)입니다.
왜 발생하는가?
운영체제는 가상 메모리 기법을 사용하여 실제 물리 메모리보다 큰 주소 공간을 프로세스에 제공합니다. 모든 페이지를 물리 메모리에 올려두지 않고, 필요한 시점에 로드하는 요구 페이징(Demand Paging) 방식을 사용하기 때문에 페이지 폴트가 발생합니다.
페이지 폴트 처리 흐름
① 프로세스가 가상 주소 접근
② MMU가 페이지 테이블 조회
③ Valid Bit = 0 → 물리 메모리에 없음
④ Page Fault 예외 발생 (벡터 14)
⑤ CPU → IDT[14] → 페이지 폴트 핸들러 진입 (커널 모드)
⑥ 커널이 원인 분석
├── 유효한 접근 → 디스크에서 페이지 로드
└── 잘못된 접근 → 프로세스 종료 (Segmentation Fault)
⑦ 빈 프레임 확보 (없으면 페이지 교체 알고리즘 실행)
⑧ 디스크 → 물리 메모리로 페이지 복사
⑨ 페이지 테이블 갱신 (Valid Bit = 1, 프레임 번호 기록)
⑩ 원래 명령어 재실행 (Fault이므로 같은 명령어로 복귀)
** MMU
프로세스: arr[1000] 접근
│
▼
MMU: 페이지 테이블 조회 → Valid Bit = 0
│
▼
Page Fault 발생 → 커널 모드 전환
│
├── 유효한 접근?
│ ├── Yes → 디스크에서 페이지 로드 → 테이블 갱신 → 재실행
│ └── No → SIGSEGV → 프로세스 종료
│
▼
arr[1000] 재실행 → 성공
페이지 테이블 엔트리 구조
┌─────────────────────────────────────────────┐
│ 프레임 번호 │ Valid │ Dirty │ Reference │ 권한(R/W/X) │
└─────────────────────────────────────────────┘
| 비트 | 설명 |
|---|---|
| Valid | 1: 물리 메모리에 존재 / 0: 부재 → 페이지 폴트 |
| Dirty | 1: 페이지가 수정됨 → 교체 시 디스크에 기록 필요 |
| Reference | 1: 최근 참조됨 → 페이지 교체 알고리즘에서 활용 |
| 권한 | 읽기/쓰기/실행 권한 → 위반 시 Protection Fault |
페이지 폴트의 종류
| 종류 | 설명 | 처리 |
|---|---|---|
| Minor (Soft) | 페이지가 이미 메모리에 있지만 매핑만 안 된 경우 | 페이지 테이블만 갱신 (빠름) |
| Major (Hard) | 페이지가 디스크에만 존재, 물리 메모리에 없음 | 디스크 I/O 필요 (느림) |
| Invalid | 존재하지 않는 주소 접근 (잘못된 접근) | 프로세스 종료 (Segfault) |
페이지 폴트
│
├── Minor Fault ── 메모리에 있음, 매핑만 필요 ── ~수 μs
│ ex) 공유 라이브러리가 이미 다른 프로세스에 의해 로드됨
│
├── Major Fault ── 디스크에서 로드 필요 ──────── ~수 ms
│ ex) 최초 접근, 스왑 아웃된 페이지
│
└── Invalid ────── 잘못된 주소 접근 ──────────── 프로세스 종료
ex) NULL 포인터, 할당되지 않은 영역
빈 프레임이 없을 때 — 페이지 교체 알고리즘
| 알고리즘 | 설명 | 특징 |
|---|---|---|
| FIFO | 가장 먼저 들어온 페이지 교체 | 단순하지만 Belady's Anomaly 발생 가능 |
| LRU | 가장 오래 사용되지 않은 페이지 교체 | 성능 우수, 구현 비용 높음 |
| LFU | 사용 빈도가 가장 낮은 페이지 교체 | 최근 로드된 페이지에 불리 |
| Clock (Second Chance) | Reference Bit 활용, FIFO 개선 | LRU 근사, 실제 OS에서 많이 사용 |
| OPT | 미래에 가장 늦게 사용될 페이지 교체 | 이론적 최적해, 실제 구현 불가 |
[Clock 알고리즘 예시]
──→ [A, ref=1] → [B, ref=0] → [C, ref=1] → [D, ref=0]
포인터 ─┘
교체 필요 시:
① A(ref=1) → ref=0으로 변경, 넘어감
② B(ref=0) → 교체 대상! B를 내보내고 새 페이지 로드
스레싱 (Thrashing)
페이지 폴트가 과도하게 발생하여 CPU가 실제 작업보다 페이지 교체에 대부분의 시간을 소비하는 현상입니다.
| 항목 | 내용 |
|---|---|
| 원인 | 물리 메모리 부족, 너무 많은 프로세스 동시 실행 |
| 증상 | CPU 사용률 급락, 디스크 I/O 급증 |
| 해결 | 프로세스 수 줄이기, 메모리 증설, Working Set 모델 적용 |
정상 상태: CPU 사용률 ↑, 페이지 폴트 적음
│
▼ 프로세스 계속 추가
│
스레싱: CPU 사용률 ↓↓, 디스크 I/O ↑↑
→ 페이지 로드 → 다른 페이지 교체 → 또 폴트 → 무한 반복
Java에서의 페이지 폴트
// 1. 큰 배열 할당 — 가상 메모리만 확보, 실제 물리 메모리 할당은 접근 시
byte[] huge = new byte[100 * 1024 * 1024]; // 100MB 가상 메모리 확보
huge[0] = 1; // 첫 페이지 접근 → Major Page Fault
huge[4096] = 1; // 다음 페이지 접근 → Major Page Fault
huge[50_000_000] = 1; // 또 다른 페이지 → Major Page Fault
// 2. 메모리 매핑 파일 — 파일 내용을 접근할 때마다 페이지 폴트 발생 가능
FileChannel fc = FileChannel.open(Path.of("large.dat"));
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
byte b = mbb.get(0); // 해당 오프셋 페이지가 없으면 Page Fault
byte b2 = mbb.get(1_000_000); // 다른 위치 접근 시 또 Page Fault 가능
// 3. 클래스 로딩 — JVM이 .class 파일을 메모리에 로드할 때
Class<?> clazz = Class.forName("com.example.MyClass");
// 해당 클래스 파일이 메모리에 없으면 Page Fault → 디스크에서 로드