콘텐츠로 이동

Virtual Memory

물리 메모리의 크기 한계를 극복하기 위해 나온 기술로, 프로세스 전체가 메모리에 적재되지 않아도 실행이 가능하다는 점에 착안하여 설계되었다.

  • 실제 물리 메모리보다 큰 프로세스를 실행 가능
  • 멀티태스킹 환경에서 더 많은 프로세스 수용 가능

프로세스의 논리 주소 공간과 물리 메모리 공간을 일정한 크기의 단위로 나누어 관리하는 기법으로, 연속 메모리 할당의 문제점인 외부 단편화를 해결하는 핵심 기술이다.

  • 페이지(Page): 프로세스의 논리 주소 공간을 나눈 단위
  • 프레임(Frame): 물리 메모리 공간을 페이지와 동일한 크기로 나눈 단위

일정한 단위로 자른 뒤 페이지를 임의의 프레임에 불연속적으로 할당하게 되는데, 페이지 번호와 프레임 번호를 짝지어 논리적으로 연속된 것처럼 동작한다.

물리 메모리에 불연속적으로 저장된 페이지들을 CPU가 연속적인 논리 주소로 인식하고 실행할 수 있도록 돕는 매핑 테이블이다.

  • 각 프로세스마다 별도의 페이지 테이블을 가짐
  • 주로 PCB(프로세스 제어 블록)에 포인터가 저장
  • 매핑 정보: 페이지 번호(Page Number)와 그에 매칭되는 프레임 번호(Frame Number)를 저장
  • 논리 주소 변환: CPU가 내는 논리 주소를 페이지 테이블을 참조하여 물리 주소로 변환함
  • 주요 필드: 프레임 번호 외에도 유효 비트(Valid Bit), 보호 비트(Protection Bit), 참조 비트(Reference Bit), 수정 비트(Dirty Bit) 등을 포함하여 페이지 상태를 관리함

요구 페이징(Demand Paging)과 스와핑

섹션 제목: “요구 페이징(Demand Paging)과 스와핑”

페이징 시스템에서는 프로세스 실행 시 모든 페이지를 미리 메모리에 올리지 않고, 실행에 필요한 페이지만 메모리에 적재하는 기법을 사용한다.

  • 페이지 인(Page In): 필요한 페이지를 보조기억장치(스왑 영역)에서 메모리로 읽어 들이는 작업
  • 페이지 아웃(Page Out): 메모리가 부족하거나 당장 필요하지 않은 페이지를 스왑 영역으로 내보내는 작업
  • 스와핑 효과: 이 과정을 통해 실제 메모리보다 훨씬 큰 용량의 프로세스를 실행하는 환상을 제공함

CPU가 액세스하려는 페이지가 현재 물리 메모리에 없을 때(유효 비트가 0일 때) 발생하는 동기 예외(synchronous exception/fault)로, CPU가 명령어 실행 중 발생시킨다.

sequenceDiagram
participant CPU
participant OS as 운영체제 (커널)
participant PageTable as 페이지 테이블
participant Disk as 디스크 (스왑 영역)
participant Memory as 물리 메모리
CPU ->> PageTable: 1. 논리 주소 요청
PageTable -->> CPU: 2. 유효 비트 0 확인 (Trap 발생)
Note over CPU,OS: 3. 페이지 폴트 인터럽트 발생
OS ->> Disk: 4. 해당 페이지 위치 탐색 및 읽기 요청
Disk ->> Memory: 5. 빈 프레임에 페이지 로드
Memory -->> PageTable: 6. 페이지 테이블 업데이트 (유효 비트 1 설정)
OS ->> CPU: 7. 명령어 재실행 (Resume)
  1. CPU가 페이지 참조 시도
  2. 페이지 테이블에서 해당 페이지가 메모리에 없음을 확인(Invalid)
  3. 페이지 폴트 트랩(Trap) 발생하여 운영체제로 제어권 이동
  4. 운영체제는 보조기억장치에서 해당 페이지를 찾음
  5. 물리 메모리의 빈 프레임에 페이지를 적재 (빈 프레임이 없으면 페이지 교체 알고리즘 가동)
  6. 페이지 테이블을 갱신하고 트랩이 발생했던 명령어를 다시 실행

요구 페이징은 페이지 폴트의 가장 대표적 용도지만, 운영체제는 같은 메커니즘을 여러 곳에 응용한다.

운영체제는 0번 주소 근처 페이지를 일부러 비워둔다.

  • 자바의 null이나 C의 NULL은 메모리 주소 0으로 표현
  • null 참조의 필드를 읽으면 결과적으로 0번 주소 근처에 접근과 같은 효과 → 페이지 폴트 발생
  • 페이지 폴트 발생하면서 커널이 SIGSEGV 시그널 전달
  • JVM 같은 런타임은 이 시그널을 핸들러로 가로채 NullPointerException으로 변환

덕분에 JIT는 매번 null 검사 분기를 박는 대신, 핫 패스에서 검사를 생략해도 안전하게 NPE를 던질 수 있다.

스택 가드 페이지 (Stack Guard Page)

섹션 제목: “스택 가드 페이지 (Stack Guard Page)”

스택 끝에 매핑되지 않은 페이지를 한 장 두어 스택 오버플로를 검출한다.

  • 재귀가 너무 깊거나 큰 변수를 할당해 스택이 가드 페이지를 침범하면 즉시 폴트 발생
  • 커널은 이 폴트를 스택 오버플로로 판단하고 프로세스를 안전하게 종료

페이징은 외부 단편화는 완벽히 해결하지만, 내부 단편화라는 문제가 발생하기 때문에, 프로세스의 크기가 페이지 크기의 정수배가 아닐 경우, 마지막 페이지의 남은 공간은 사용되지 않고 낭비된다.

  • 예시: 페이지 크기가 10KB이고 프로세스 크기가 32KB인 경우
    • 10KB 페이지 3개 할당 (30KB)
    • 마지막 2KB를 위해 10KB 페이지 1개 추가 할당
    • 결과: 40KB 할당 중 8KB는 사용되지 않는 내부 단편화 발생
  • 해결책: 페이지 크기를 너무 크게 잡지 않는 것이 중요하나, 너무 작으면 페이지 테이블의 크기가 커지는 트레이드오프가 존재

마지막 업데이트:

Operating System