가상 메모리와 페이지 테이블
가상 주소, 물리 주소, TLB와 페이지 폴트의 흐름
본 블로그 작성 글들은, 강의를 목표로 하고 제작되었습니다. 또한 작성된 글의 정보도 틀렸을 수 있으니, 주의해주세요.
프로그램이 사용하는 포인터 값은 보통 RAM 칩의 물리 위치를 그대로 나타내지 않는다. 운영체제와 CPU는 프로세스마다 독립적인 가상 주소 공간을 제공하고 필요한 부분을 실제 물리 메모리에 연결한다.
가상 주소를 물리 주소로 변환한다
프로세스가 가상 주소에 접근
↓
CPU가 페이지 번호와 페이지 내부 위치로 분리
↓
페이지 테이블에서 물리 프레임을 찾음
↓
물리 메모리에 접근
메모리는 일정 크기의 페이지 단위로 관리된다. 가상 페이지는 RAM의 물리 프레임에 연결될 수도 있고 아직 연결되지 않았거나 접근이 금지된 상태일 수도 있다.
프로세스마다 별도의 주소 공간을 사용하면 같은 가상 주소가 서로 다른 물리 메모리를 가리킬 수 있다. 한 프로세스가 다른 프로세스의 메모리를 임의로 읽지 못하게 보호하고, 프로그램은 물리 RAM의 배치를 직접 관리하지 않아도 된다.
페이지 테이블이 매핑과 권한을 기록한다
페이지 테이블 항목에는 물리 프레임 번호뿐 아니라 읽기, 쓰기, 실행 가능 여부와 현재 메모리에 존재하는지 같은 상태가 기록될 수 있다.
가상 페이지 0x120 → 물리 프레임 0x08A, Read/Write
가상 페이지 0x121 → 물리 프레임 0x04F, Read Only
가상 페이지 0x122 → 매핑 없음
코드 영역을 읽기·실행 가능하지만 쓰기 불가능하게 두거나, 읽기 전용 데이터를 보호하는 것도 이 권한을 이용한다. 권한이 없는 페이지에 접근하면 운영체제는 프로세스에 접근 위반을 알린다.
페이지 테이블 자체도 커질 수 있으므로 실제 시스템은 여러 단계의 계층 구조와 필요할 때만 만드는 테이블을 사용한다. 정확한 단계 수와 페이지 크기는 CPU 아키텍처와 운영체제 설정에 따라 달라진다.
TLB는 최근 주소 변환을 기억한다
메모리에 접근할 때마다 페이지 테이블을 여러 번 읽으면 실제 데이터 한 번을 얻기 위해 추가 메모리 접근이 반복된다. CPU는 최근 가상 페이지와 물리 프레임의 변환을 TLB(Translation Lookaside Buffer)에 저장한다.
가상 주소 접근
├─ TLB hit → 바로 물리 주소 사용
└─ TLB miss → 페이지 테이블 탐색 후 TLB 갱신
큰 데이터에서 페이지를 여기저기 건너뛰며 접근하면 캐시뿐 아니라 TLB 적중률도 낮아질 수 있다. Huge Page는 한 항목이 더 큰 메모리 범위를 담당하게 해 TLB 부담을 줄일 수 있지만 메모리 낭비와 관리 비용도 함께 고려해야 한다.
페이지 폴트는 항상 오류가 아니다
현재 페이지 테이블만으로 접근을 완료할 수 없으면 페이지 폴트가 발생한다. 운영체제는 원인을 확인한 뒤 다음처럼 처리할 수 있다.
- 처음 접근한 익명 메모리에 실제 물리 페이지를 할당한다.
- 파일에서 필요한 페이지를 읽어온다.
- Copy-on-Write 페이지를 복사해 쓰기 가능한 새 페이지를 만든다.
- 접근 권한이 없다면 프로세스에 오류를 전달한다.
따라서 페이지 폴트가 모두 디스크 스왑을 뜻하지는 않는다. 하지만 저장 장치에서 데이터를 가져와야 하는 major page fault는 RAM 접근보다 훨씬 긴 지연을 만들 수 있다.
가상 메모리는 실제 메모리를 무한하게 만드는 기능이 아니다. 주소 공간의 격리와 보호, 공유, 지연 할당을 가능하게 하지만 작업 집합이 물리 메모리를 크게 넘으면 페이지 교체가 반복되어 시스템이 매우 느려질 수 있다.