Page Fault: 가상 메모리와 물리 메모리 사이의 부재 신호
Page Fault는 프로세스가 접근하려는 가상 주소에 대응하는 페이지가 물리 메모리(RAM)에 없을 때 발생하는 예외(exception)다. CPU가 MMU(Memory Management Unit)를 통해 주소 변환을 시도하다 실패하면 트랩(trap)을 발생시키고, 운영체제 커널이 개입해 페이지를 메모리로 적재하거나 프로세스를 종료시킨다. 단순 오류가
By 송민성
1. 개념
Page Fault는 CPU가 가상 주소(virtual address)를 물리 주소(physical address)로 변환하는 과정에서, 해당 가상 페이지에 대응하는 물리 페이지 프레임이 현재 메모리에 적재되어 있지 않을 때 발생하는 하드웨어 예외다.
프로세스는 자신만의 가상 주소 공간(virtual address space)에서 동작하고, 실제 데이터는 물리 메모리 어딘가에 흩어져 있거나 디스크(스왑 영역, 실행 파일)에 존재할 수 있다. 페이지 테이블(page table)의 각 엔트리에는 유효 비트(valid/present bit)가 있는데, 이 비트가 0이면 해당 페이지가 물리 메모리에 없다는 뜻이고 이때 Page Fault가 발생한다.
Page Fault는 이름과 달리 "장애"나 "오류"가 아니라 정상적인 신호에 가깝다. 운영체제는 이 신호를 받아 필요한 페이지를 디스크에서 읽어와 물리 메모리에 적재한 뒤, 페이지 테이블을 갱신하고 원래 실행을 중단 없이 이어가게 한다.
2. 왜 사용하는가
물리 메모리는 유한하지만 프로세스가 요구하는 주소 공간은 이보다 훨씬 클 수 있다. 모든 페이지를 미리 메모리에 올려두면 다음 문제가 생긴다.
- 실행 파일 전체를 한 번에 로드하면 시작 시간이 길어지고, 실제로 쓰이지 않는 코드/데이터까지 메모리를 차지한다.
- 여러 프로세스가 동시에 실행될 때 물리 메모리보다 큰 총 요구량을 감당할 수 없다.
Page Fault를 이용한 Demand Paging(요구 페이징) 방식은 페이지를 "실제로 접근하는 시점"에만 메모리로 가져온다. 이를 통해:
- 프로세스 시작 시간이 단축된다.
- 물리 메모리보다 큰 가상 주소 공간을 프로세스에 제공할 수 있다(가상 메모리의 핵심 가치).
- 메모리 부족 시 자주 쓰이지 않는 페이지를 디스크로 내보내고(swap-out), 그 공간을 다른 프로세스에 재할당할 수 있다.
3. 동작 원리
Page Fault 처리 흐름은 대략 다음과 같다.
- CPU가 가상 주소를 참조하는 명령어를 실행한다.
- MMU가 TLB(Translation Lookaside Buffer)를 먼저 조회한다. TLB 미스가 나면 페이지 테이블을 조회한다.
- 페이지 테이블 엔트리의 valid bit가 0이면 하드웨어가 트랩(trap)을 발생시켜 CPU 제어권을 커널의 Page Fault Handler로 넘긴다.
- 커널은 폴트가 발생한 가상 주소가 유효한 주소 공간(예: 프로세스에 매핑된 영역)인지 검사한다.
- 유효하지 않으면 Segmentation Fault로 처리하고 프로세스에 SIGSEGV 시그널을 보낸다. - 유효하면 다음 단계로 진행한다.
- 빈 물리 프레임을 확보한다. 여유 프레임이 없으면 페이지 교체 알고리즘(LRU, Clock 등)으로 희생 페이지(victim page)를 선택해 필요 시 디스크로 스왑아웃한다.
- 디스크(스왑 영역 또는 실행 파일)에서 필요한 페이지 데이터를 물리 프레임으로 읽어온다.
- 페이지 테이블 엔트리를 갱신해 valid bit를 1로 설정하고 물리 프레임 번호를 기록한다.
- 폴트를 유발한 명령어를 처음부터 다시 실행한다(restart instruction).
Page Fault는 종류에 따라 구분된다.
- Minor Fault(soft fault): 페이지가 디스크 I/O 없이 이미 메모리 어딘가(예: 파일 캐시, 다른 프로세스와 공유된 페이지)에 있어서 매핑만 다시 걸어주면 되는 경우. 처리 비용이 낮다.
- Major Fault(hard fault): 실제로 디스크에서 데이터를 읽어와야 하는 경우. 디스크 I/O 지연 때문에 처리 비용이 훨씬 크다(밀리초 단위, RAM 접근 대비 수천~수만 배 느림).
- Invalid Fault: 프로세스에 할당되지 않은 주소 접근. Segmentation Fault로 이어진다.
4. 코드 예제
Page Fault 자체는 커널/하드웨어 영역이라 애플리케이션 코드로 직접 트리거하거나 관찰하는 예제를 든다.
# Linux에서 프로세스의 minor/major page fault 횟수 확인
# ps -o min_flt,maj_flt 컬럼으로 확인 가능
ps -o pid,comm,min_flt,maj_flt -p $(pgrep -n python3)
# /usr/bin/time으로 프로그램 실행 중 발생한 fault 통계 확인
/usr/bin/time -v python3 large_array.pyimport mmap
import os
# 큰 파일을 메모리 매핑(mmap)하면 실제로 접근하는 시점에
# Page Fault를 통해 페이지가 물리 메모리로 로드된다 (지연 로딩)
path = "large_file.bin"
with open(path, "rb") as f:
size = os.path.getsize(f.fileno())
# 파일 전체를 가상 주소 공간에 매핑만 함. 아직 물리 메모리에 올라가지 않음
mm = mmap.mmap(f.fileno(), size, access=mmap.ACCESS_READ)
# 이 시점에 실제로 해당 오프셋의 페이지를 처음 읽으면
# 매핑된 적 없는 페이지라 Page Fault(major fault)가 발생하고
# 커널이 디스크에서 페이지를 읽어 물리 메모리에 적재한다
chunk = mm[0:4096]
print(len(chunk))
mm.close()# strace로 실제 page fault 관련 시스템 콜 흐름을 관찰 (mmap, mincore 등)
strace -c python3 large_array.py5. 시간 복잡도 또는 성능 특성
Page Fault는 알고리즘적 시간복잡도보다 "비용(latency)" 관점에서 이해하는 게 중요하다.
- RAM 접근 지연: 대략 100나노초 내외
- Minor Fault 처리: 마이크로초(µs) 단위. 페이지 테이블 갱신과 매핑만 필요하므로 상대적으로 저렴하다.
- Major Fault 처리: 디스크(HDD 기준 수 밀리초, SSD 기준 수십~수백 마이크로초) I/O가 개입하므로 RAM 접근 대비 수천 배 이상 느려질 수 있다.
Major Fault가 과도하게 자주 발생하는 상태를 스래싱(Thrashing)이라 부른다. 물리 메모리가 부족해 프로세스들이 서로의 페이지를 계속 스왑아웃/스왑인하면서, CPU가 실제 연산보다 페이지 교체에 더 많은 시간을 쓰게 되어 시스템 전체 처리량이 급격히 떨어진다.
6. 실무 사용 사례
- mmap 기반 파일 I/O: 대용량 파일(로그, 데이터셋)을 read/write 시스템 콜 대신 mmap으로 매핑하면, 실제로 접근한 부분만 Page Fault를 통해 로드되어 메모리 효율이 좋아진다. PostgreSQL, Redis(RDB 로딩 일부), 다양한 데이터베이스 엔진이 이 방식을 활용한다.
- Copy-on-Write(COW): fork() 시스템 콜로 자식 프로세스를 만들 때 부모의 페이지를 즉시 복사하지 않고 공유한다. 이후 어느 한쪽이 쓰기(write) 시도를 하면 Page Fault가 발생해 그 시점에 실제 복사가 일어난다. Linux fork()의 성능 최적화 핵심 메커니즘이다.
- 컨테이너/VM 메모리 오버커밋: 클라우드 환경에서 실제 물리 메모리보다 많은 가상 메모리를 여러 VM에 할당하고, Page Fault 기반 지연 로딩으로 실사용량만큼만 물리 메모리를 소비하게 한다.
- JVM/Node.js 힙 관리: 힙을 크게 예약(reserve)해두고 실제 사용하는 만큼만 커밋(commit)해서, 필요한 시점에 Page Fault로 물리 메모리를 확보한다.
7. 주의할 점
- Page Fault는 정상적인 메커니즘이지만 과도하면 성능 문제(스래싱)로 이어진다. 물리 메모리가 부족한 서버에서 Major Fault 비율이 급증하면 애플리케이션 응답 시간이 갑자기 늘어날 수 있다.
- 모니터링 시
vmstat,sar -B같은 도구로 초당 Page Fault 수(특히 major fault,majflt)를 확인하는 게 실질적인 진단 방법이다. - 컨테이너 환경에서 메모리 제한(cgroup memory limit)을 너무 타이트하게 걸면, 스왑이 비활성화된 상태에서 OOM Killer가 개입해 Page Fault 처리 전에 프로세스가 강제 종료될 수 있다.
- 실시간성이 중요한 시스템(임베디드, 저지연 트레이딩 시스템)에서는 Page Fault 자체의 지연이 예측 불가능한 지연(jitter)을 유발하므로, mlock()/mlockall() 같은 시스템 콜로 특정 메모리 영역을 물리 메모리에 고정(pin)해 스왑 대상에서 제외하기도 한다.
8. 핵심 정리
Page Fault는 가상 주소에 대응하는 물리 페이지가 메모리에 없을 때 발생하는 예외이며, 운영체제가 이를 처리해 가상 메모리 시스템이 물리 메모리보다 큰 주소 공간을 제공할 수 있게 하는 핵심 메커니즘이다. Minor Fault는 저비용 매핑 갱신이고 Major Fault는 디스크 I/O를 동반해 훨씬 비싸며, 이 차이를 이해하는 것이 성능 문제(스래싱)를 진단하는 출발점이다. mmap, Copy-on-Write, 컨테이너 메모리 오버커밋 등 실무의 여러 메모리 최적화 기법이 Page Fault를 적극적으로 활용한다.