운영체제Medium#084
가상 메모리(Virtual Memory)란 무엇이며, 페이징(Paging)은 어떻게 동작하나요?
#OS#가상메모리#페이징#메모리관리
답변 포인트
물리 메모리보다 큰 프로그램을 실행할 수 있는 이유를 생각해보세요.
정답 및 해설
빠른 요약
가상 메모리는 실제 물리 메모리보다 큰 주소 공간을 프로세스에 제공하는 기술입니다. 동작 원리: - 프로세스의 주소 공간을 일정 크기의 페이지(Page)로 나눔 - 물리 메모리(프레임)와 페이지 테이블로 매핑 - 현재 필요한 페이지만 물리 메모리에 로드 (요구 페이징) Page Fault: - 필요한 페이지가 물리 메모리에 없을 때 발생 - OS가 디스크에서 해당 페이지를 메모리로 로드 장점: 메모리 효율 향상, 프로세스 간 격리 단점: 페이지 폴트 시 디스크 I/O로 성능 저하 가능
가상 메모리(Virtual Memory)는 프로세스에게 실제 물리 메모리(RAM)보다 더 큰 주소 공간을 제공하는 메모리 관리 기술입니다. 각 프로세스는 독립된 가상 주소 공간을 가지므로 서로의 메모리 영역에 접근할 수 없어 보안과 격리성이 보장됩니다. 실제로 필요한 페이지만 물리 메모리에 적재하고 나머지는 디스크에 보관함으로써 메모리를 효율적으로 활용합니다.
가상 메모리의 필요성
운영체제
물리 메모리만 사용하는 경우의 문제:
1. 메모리 크기 제한: 실행 가능한 프로세스 수가 RAM 크기에 종속됨
2. 메모리 단편화: 프로세스가 연속된 물리 메모리를 요구
3. 보안 문제: 한 프로세스가 다른 프로세스의 메모리에 접근 가능
4. 메모리 관리 복잡성: 프로그래머가 메모리 배치를 직접 관리해야 함
가상 메모리가 해결하는 것:
- 32비트 프로세스: 4GB 가상 주소 공간 (물리 메모리와 무관)
- 64비트 프로세스: 수 TB의 가상 주소 공간
- 프로세스 간 완전한 격리
- 페이지 단위의 효율적 메모리 관리페이징(Paging) 기본 개념
주요 용어
운영체제
가상 메모리
┌────────────────────────────────────────────────────────┐
│ Page 0 │ Page 1 │ Page 2 │ Page 3 │ Page 4 │ Page 5 │
└────────────────────────────────────────────────────────┘
4KB 4KB 4KB 4KB 4KB 4KB
물리 메모리 (RAM)
┌─────────────────────────────────────────┐
│ Frame 0 │ Frame 1 │ Frame 2 │ Frame 3 │
└─────────────────────────────────────────┘
4KB 4KB 4KB 4KB
디스크 (스왑 영역)
┌──────────────────────────────────────────────────────┐
│ Swap Page │ Swap Page │ Swap Page │ Swap Page │ ... │
└──────────────────────────────────────────────────────┘
Page: 가상 메모리를 고정 크기로 분할한 단위 (보통 4KB)
Frame: 물리 메모리를 Page 크기로 분할한 단위
Page Table: 가상 페이지 번호 → 물리 프레임 번호 매핑 테이블페이지 테이블(Page Table)
구조와 주소 변환
운영체제
가상 주소 구조 (32비트, 4KB 페이지):
┌─────────────────────────┬───────────────┐
│ 가상 페이지 번호(VPN) │ 페이지 오프셋 │
│ (20비트) │ (12비트) │
└─────────────────────────┴───────────────┘
2^20 = 1M 페이지 2^12 = 4KB
주소 변환 과정:
가상 주소: VPN=5, Offset=100
│
▼ Page Table 조회
Page Table:
VPN 0 → Frame 3 (물리 메모리에 있음)
VPN 1 → Frame 7 (물리 메모리에 있음)
VPN 2 → Disk (스왑 영역에 있음, Present bit=0)
VPN 5 → Frame 2 (물리 메모리에 있음)
│
▼
물리 주소: Frame=2, Offset=100
물리 주소 = Frame번호 × Page크기 + Offset
= 2 × 4096 + 100
= 8292페이지 테이블 엔트리 구조
운영체제
각 PTE (Page Table Entry)의 비트 구성:
┌────────┬────────┬─────────┬──────────┬────────────────┐
│ Present│ Dirty │Accessed │Protection│ Frame Number │
│ (P) │ (D) │ (A) │ (R/W/X) │ │
└────────┴────────┴─────────┴──────────┴────────────────┘
Present bit (P): 1 = 물리 메모리에 있음, 0 = 디스크에 있음
Dirty bit (D): 1 = 페이지 수정됨 (스왑 아웃 시 디스크에 기록 필요)
Accessed bit (A): 최근 접근 여부 (페이지 교체 알고리즘에 사용)
Protection: 읽기/쓰기/실행 권한TLB (Translation Lookaside Buffer)
페이지 테이블 조회의 성능 문제
운영체제
TLB 없이 메모리 접근:
1. 가상 주소에서 VPN 추출
2. 페이지 테이블 접근 (메모리 접근 1회)
3. 물리 주소 획득
4. 실제 데이터 접근 (메모리 접근 1회)
→ 총 2번의 메모리 접근 (2배 오버헤드)TLB를 사용한 성능 최적화
운영체제
TLB: 최근에 사용한 페이지 테이블 엔트리를 캐싱하는 하드웨어
CPU 내부에 위치, 매우 빠름 (수 사이클)
일반적으로 64~1024개 엔트리
TLB Hit (약 99%):
가상 주소 → TLB 조회 → 물리 주소 직접 획득 → 데이터 접근
→ 1번의 메모리 접근
TLB Miss:
가상 주소 → TLB 조회 실패 → 페이지 테이블 접근 → TLB 갱신
→ 물리 주소 획득 → 데이터 접근
→ 2번의 메모리 접근
성능:
유효 메모리 접근 시간 = hit_rate × TLB_time + miss_rate × (TLB_time + PT_access_time)
= 0.99 × 1ns + 0.01 × (1ns + 100ns) ≈ 2ns (vs 200ns for two memory accesses)페이지 폴트 (Page Fault)
발생 과정
운영체제
프로세스가 가상 주소에 접근
│
▼
TLB 조회
│
TLB Hit?
┌─────┴─────┐
YES NO
│ │
물리 주소 페이지 테이블 조회
획득 │
Present bit = 1?
┌─────┴─────┐
YES NO
│ │
물리 주소 ★ 페이지 폴트 발생!
획득 │
▼
OS 핸들러 호출
│
디스크에서 페이지 로드
│
빈 프레임에 적재
│
페이지 테이블 갱신
│
프로세스 재개페이지 폴트 처리 과정 상세
운영체제
1. CPU가 페이지 폴트 인터럽트 발생
2. 현재 프로세스 상태 저장 (PCB)
3. OS 페이지 폴트 핸들러 실행
4. 해당 가상 주소가 유효한지 확인
- 유효하지 않으면 SIGSEGV (Segmentation Fault) 발생
5. 디스크(스왑 영역)에서 페이지 로드
6. 빈 물리 프레임 확보
- 빈 프레임이 없으면 페이지 교체 알고리즘 실행
7. 페이지 테이블 및 TLB 업데이트
8. 프로세스 재개Java에서의 페이지 폴트 영향
Java
// 대용량 배열 초기화 시 페이지 폴트 발생
public class PageFaultExample {
// 처음 접근 시 페이지 폴트 발생 → 점차 빨라짐
public static void main(String[] args) {
int size = 1024 * 1024; // 1M int = 4MB
int[] largeArray = new int[size]; // 메모리 할당만, 아직 물리 페이지 미할당
long start = System.nanoTime();
for (int i = 0; i < size; i++) {
largeArray[i] = i; // 처음 접근 시 페이지 폴트 발생
}
System.out.println("소요 시간: " + (System.nanoTime() - start) + "ns");
// 두 번째 실행: 페이지가 이미 메모리에 있으므로 훨씬 빠름
start = System.nanoTime();
for (int i = 0; i < size; i++) {
largeArray[i] = i * 2;
}
System.out.println("두 번째 소요 시간: " + (System.nanoTime() - start) + "ns");
}
}페이지 교체 알고리즘
물리 메모리가 가득 찼을 때, 어떤 페이지를 내보낼지 결정합니다.
주요 알고리즘
운영체제
1. OPT (Optimal, 이론적 최적):
미래에 가장 오랫동안 사용되지 않을 페이지 교체
→ 미래를 알 수 없어 실제 구현 불가, 성능 기준점으로 사용
2. FIFO (First In First Out):
가장 오래전에 적재된 페이지 교체
→ Belady's Anomaly: 프레임 수를 늘려도 폴트가 증가할 수 있음
3. LRU (Least Recently Used): 가장 많이 사용
가장 오랫동안 사용되지 않은 페이지 교체
→ 지역성(Locality) 원리에 기반, 성능 우수
→ 구현 비용: 참조 시마다 타임스탬프 또는 스택 갱신 필요
4. LFU (Least Frequently Used):
참조 횟수가 가장 적은 페이지 교체
→ 초기에 많이 사용되고 이후 불필요한 페이지가 남을 수 있음
5. Clock (NRU - Not Recently Used): Linux 근사 LRU
페이지에 Reference bit 사용, 원형으로 순환하며 교체 대상 선택
→ LRU의 근사, 구현 효율적LRU 알고리즘 예시
운영체제
물리 프레임 3개, 페이지 참조 순서: 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3
참조 | 프레임 상태 | 폴트
─────────────────────────────────────
7 | [7, -, -] | ★
0 | [7, 0, -] | ★
1 | [7, 0, 1] | ★
2 | [2, 0, 1] | ★ (7 교체 - 가장 오래 미사용)
0 | [2, 0, 1] | (0이 있음)
3 | [2, 0, 3] | ★ (1 교체)
0 | [2, 0, 3] | (0이 있음)
4 | [4, 0, 3] | ★ (2 교체)
...
총 페이지 폴트 수 계산 후 성능 비교가상 메모리와 스와핑
운영체제
물리 메모리 부족 시:
1. 페이지 교체 알고리즘으로 희생 페이지(victim page) 선택
2. Dirty bit = 1이면 디스크(스왑)에 기록
3. 새 페이지 로드
4. 페이지 테이블 업데이트
스래싱(Thrashing):
- 메모리 부족으로 페이지 폴트가 너무 많이 발생
- 페이지 교체에 대부분의 시간을 소비
- CPU 이용률 급감
- 해결: 다중 프로그래밍 정도 감소, 워킹 셋(Working Set) 알고리즘요약 표
| 개념 | 설명 | 역할 |
|---|---|---|
| 가상 주소 | 프로세스가 사용하는 논리적 주소 | 프로세스 격리, 큰 주소 공간 제공 |
| 물리 주소 | 실제 RAM의 주소 | 실제 데이터 저장 위치 |
| 페이지 (Page) | 가상 메모리의 고정 크기 단위 (4KB) | 가상 메모리 분할 |
| 프레임 (Frame) | 물리 메모리의 고정 크기 단위 (4KB) | 물리 메모리 분할 |
| 페이지 테이블 | VPN → Frame 번호 매핑 | 주소 변환 |
| TLB | 페이지 테이블 캐시 (하드웨어) | 주소 변환 속도 향상 |
| 페이지 폴트 | 요청 페이지가 물리 메모리에 없음 | OS가 디스크에서 로드 |
| 스왑 영역 | 디스크의 임시 메모리 공간 | 물리 메모리 확장 |
| 페이지 교체 알고리즘 | 기준 | 구현 복잡도 | 성능 |
|---|---|---|---|
| OPT | 미래 최장 미사용 | 불가 (이론) | 최적 |
| FIFO | 가장 오래 적재됨 | 낮음 | 낮음 |
| LRU | 가장 오래 미사용 | 높음 | 우수 |
| LFU | 참조 횟수 최소 | 중간 | 중간 |
| Clock | NRU 근사 | 낮음 | LRU와 유사 |