세그멘테이션 또는 페이징을 적용하여 동적 재배치에 비해 내부 단편화를 줄였다.
그럼에도 불구하고 실제 시스템에서는 여러 프로세스들이 사용하는 페이지를 모두 물리 메모리에 탑재하기에는 물리 메모리 공간이 모자란 경우가 대부분이다.
이런 물리 메모리 공간의 한계를 극복하기 위해 메모리 계층에 물리 메모리보다 낮은 계층을 추가한다. 물리 메모리가 모자라거나 사용되지 않을 것이라고 판단되는 페이지를 하위 계층에 저장(스왑 swap, swap out) 하는데 보조 저장장치가 이 역할을 담당한다.
스왑을 사용함으로써 프로세스들에게 물리 메모리의 크기를 신경쓰지 않아도 되게했고(가상 주소 공간 전체를 사용할 수 있다), 이는 프로그래밍의 편리함으로 이어진다.
스왑한 페이지들을 저장할 공간을 스왑 공간 swap space라고 한다.
운영체제마다 파티션 혹은 파일의 형태로 이런 스왑 공간을 할당한다.
운영체제는 필요할 경우 스왑 공간에서 물리 메모리로 페이지를 이동시켜야 하므로 물리 메모리의 페이지 위치(물리 주소, 페이지 테이블로 저장하는) 뿐만 아니라 스왑 공간에 있는 페이지들의 디스크 주소 또한 저장해야 한다.
페이지들은 물리 메모리 또는 디스크에 위치[^다만]할 것이고, 프로세스의 메모리 접근 시 페이지가 저장된 위치를 확인해 디스크에 있다면 물리 메모리로 옮긴 후 접근하게 된다. 이런 방식으로 물리 메모리의 공간 한계를 극복할 수 있다.
[^다만]: 디스크에 위치한 페이지들이 반드시 스왑 공간에 있는 것은 아니다. 코드 세그먼트같은 경우 디스크로 스왑되더라도 스왑 공간이 아닌 실행파일 위치에 존재한다.
스왑을 사용하기 위해서는 PTE에 Present bit이 필요하다.
Present bit는 물리 메모리에 PTE에 해당하는 페이지가 존재하는 지를 나타내는 부호로 만약 0(없음)이라면 페이지가 디스크에 존재한다는 의미이다.
메모리를 참조하는 순서를 살펴보면:
TLB 미스는 시스템에 따라 하드웨어 또는 운영체제가 핸들링했던 반면 페이지 폴트는 거의 대부분 운영체제가 처리한다. 페이지 폴트 처리를 위해서는 스왑 공간의 구성 방식, 디스크 접근 등 하드웨어가 파악하기 힘든 정보들을 모두 알아야 하기 때문이다. 또한 스왑된 페이지에 대한 페이지 폴트 시에는 디스크에 접근해야 하는데 디스크에 접근하는 시간 자체가 워낙 길기 때문에, 하드웨어가 처리하도록 함에 따른 시간 절약 효과가 크지 않기 때문이기도 하다.
[^위치는]: 보통 스왑된 페이지의 디스크 상의 위치는 PTE의 PFN비트를 사용한다. 즉, present bit가 1이면 PFN에 물리 메모리 프레임 넘버를 저장하고, present bit가 0이면 PFN에 디스크의 위치를 저장한다.
지금까지 핀토스에서는 모든 메모리 페이지를 물리 메모리에 할당하여 사용하였다.
하지만 실제 운영체제에서는 프로세스들이 사용하는 메모리의 합이 머신의 실제 물리 메모리 공간보다 큰 경우가 생길 수 있다.(프로세스가 하나인 경우에도 발생할 수 있다. 일반적으로 가상주소공간은 물리 메모리 크기보다 훨씬 더 크기 때문에..)
운영체제는 이런 상황에 대비하기 위해 페이지의 일부만 물리 메모리에 적재한다.
따라서 적재되지 않은 페이지에 접근해 page fault가 발생한 경우 페이지를 적재하게 되고, 필요한 경우 적재된 페이지 중 일부를 적재해제(교체)해야 할 수 있다.
교체할 페이지(victim 페이지)를 선택하는 알고리즘을 페이지 교체 알고리즘이라고 한다.
물리 메모리는 디스크에 비해 더 빠른 접근 속도, 더 작은 용량을 가지고 있으므로 모든 페이지들을 디스크에 저장해놓고 사용할 페이지만 메모리에 가져오게 된다. 이런 관계를 고려할 때 물리 메모리는 페이지를 저장하는 캐시로 여길 수 있다.
그러한 관점에서 교체 알고리즘의 목표는 캐시 미스(페이지 폴트)를 최소화하는, 다른 말로 캐시 히트를 최대로 하는 것이라고 할 수 있다.[^교체알고리즘]
[^교체알고리즘]: 교체 알고리즘은 "무엇을 캐시할 것인가"에서 비롯된 결과물이므로 다른 캐시(TLB, cpu 캐시 등)에도 적용될 수 있다.
교체 알고리즘의 성능은 평균 메모리 접근 시간(average memory access time, AMAT)으로 측정될 수 있으며 디스크 접근 시간과 메모리 접근 시간의 접근 횟수에 대한 가중 평균이다.
가장 기본적인 일부 알고리즘만 살펴보자면:
디스크에서 물리 메모리로 이동한 뒤 페이지의 내용이 수정된 페이지를 갱신된 페이지라고 한다.
갱신된 페이지와 그렇지 않은 페이지를 구별하는 것이 필요한 이유는
이런 구분을 위해서는 modified bit(dirty bit)를 (주로 PTE에) 추가해야 한다.
페이지 교체 외에도 언제 페이지를 메모리로 불러들일 지에 대한 정책(페이지 선택 정책) 도 존재한다.
페이지 선택 정책에는 요구 페이징(demand paging)과 선반입(prefetching) 등이 있다.
요구 페이징은 페이지가 실제로 접근될 때 메모리로 읽어 들인다.
선반입은 곧 사용될 것이라고 예측되는 페이지를 미리 메모리로 읽어들인다.
변경된 페이지를 디스크에 반영하는 시점에 대한 정책도 생각해볼 수 있다.
SSD의 대중화로 그 보조 저장장치의 R/W시간이 감소하였으나 여전히 디스크를 사용하는 것은 많은 클럭 손실을 초래한다. 또한 큰 용량을 순차적으로 쓰는 것이 랜덤 쓰기보다 빠르기 때문에 많은 시스템들은 기록해야 할 페이지들을 바로 디스크에 쓰지 않고 메모리에 모았다가 한 번에 디스크에 기록한다.
가상 메모리에 있어 쓰래싱은 끊임없이 페이지를 교체하여 성능이 크게 저하되는 상황을 말한다.
메모리가 포화상태에 가까울 때나 프로세스가 요구하는 메모리가 가용 물리 메모리보다 클 때에 발생한다.
운영체제는 일부 프로세스를 종료시키는 등으로 대응한다.