Post

[운영체제 아주 쉬운 세 가지 이야기 - Virtualization] 21. Swapping - Mechanisms

[운영체제 아주 쉬운 세 가지 이야기 - Virtualization] 21. Swapping - Mechanisms

이 글은 제 개인적인 공부를 위해 작성한 글입니다.
틀린 내용이 있을 수 있고, 피드백은 환영합니다.


개요


지금까지 가상 주소 공간이 비현실적으로 작아서 모두 물리 메모리에 탑재가 가능한 것으로 가정하였다. 사실 실행 중인 프로세스의 전체 주소 공간이 메모리에 탑재된 것으로 가정하고 있었다. 이제 그 가정을 완화하여 다수의 프로세스들이 동시에 각자 큰 주소 공간을 사용하고 있는 상황을 가정한다.

이를 위해, 메모리 계층에 레이어의 추가가 필요하다. 지금까지는 모든 페이지들이 물리 메모리에 존재하는 것을 가정하였다. 하지만 더 큰 주소 공간을 지원하기 위해서 운영체제는 주소 공간 중에 현재는 크게 필요하지 않은 일부를 보관해 둘 공간이 필요하다. 일반적으로 그 공간은 메모리 공간보다 더 크며, 더 느리다. 현대 시스템에서는 보통 하드 디스크 드라이브가 이 역할을 담당한다. 이제 메모리 계층에서 크고 느린 하드 디스크 드라이브가 가장 하부에 위치하고, 그 위에 메모리가 있다. 이렇게 하면 우리의 질문은 다음과 같이 변형된다.

물리 메모리 이상으로 나아기기 위해서 어떻게 할까? 운영체제는 어떻게 크고 느린 장치를 사용하면서 마치 커다란 가장 주소 공간이 있는 것처럼 할 수 있을까?

한 가지 짚고 넘어가야 할 것은, 왜 프로세스에게 굳이 큰 주소 공간이 필요한가이다. 편리함과 사용 용이성 때문인데, 주소 공간이 충분히 크면 프로그램의 자료 구조를 위한 충분한 메모리 공간이 있는지 걱정하지 않아도 된다. 필요 시 메모리 할당을 운영체제에 요청하기만 하면 된다. 운영체제가 이러한 ‘가상’ 환경을 제공하면 인생이 편해진다.

이와 대비되는 기법으로 과거 시스템에서 사용되던 메모리 오버레이(memory overlay)가 있는데, 프로그래머가 코드 또는 데이터의 일부를 수동으로 메모리에 탑재/제거했다. 함수 호출이나 데이터 접근 시 코드 또는 데이터를 먼저 메모리에 탑재해야 하는 힘든 작업이다.

스왑 공간이 추가되면 운영체제는 실행되는 각 프로세스들에게 큰 가상 메모리가 있는 것 같은 환상을 줄 수 있다. 멀티프로그래밍 시스템이 발명되면서 많은 프로세스들의 페이지를 물리 메모리에 전부 저장하는 것이 불가능하게 되었다. 그래서 일부 페이지들을 스왑 아웃하는 기능이 필요하게 되었다. 멀티프로그래밍과 사용 편의성 등의 이유로 실제 물리 메모리보다 더 많은 용량의 메모리가 필요하게 되었다. 이것이 현대 가상 메모리의 역할이다.


스왑 공간


가장 먼저할 일은 디스크에 페이지들을 저장할 수 있는 일정 공간을 확보하는 것이다. 이 용도의 공간을 스왑 공간(swap space)이라고 한다. 스왑 공간이라고 불리는 이유는 메모리 페이지를 읽어서 이곳에 쓰고(swap out), 여기서 페이지를 읽어 메모리에 탑재시키기(swap in) 때문이다.

스왑 공간의 입출력 단위는 페이지라고 가정한다. 운영체제는 스왑 공간에 있는 모든 페이지들의 디스크 주소를 기억해야 한다.

스왑 공간의 크기는 매우 중요하다. 시스템이 사용할 수 있는 메모리 페이지의 최대수를 결정하기 때문이다. 일단 문제를 단순화하기 위해, 스왑 공간은 매우 크다고 가정하자.

아래 그림에서 물리 메모리와 스왑 공간에는 각각 4개의 페이지와 8개의 페이지를 위한 공간이 존재한다. 이 예에서는 세 개의 프로세스가 물리 메모리를 공유하고, 몇 개의 유효한 페이지들만 메모리에 올려 놓았으며 나머지 페이지들은 디스크에 스왑 아웃되어 있다. 네 번째 프로세스(Proc 3)의 모든 페이지들은 디스크로 스왑 아웃되어 있기 때문에 현재 실행 중이 아니다.

img

그리고 스왑 영역에 하나의 블럭이 비어있다. 스왑 공간을 이용하면, 시스템에 실제 물리적으로 존재하는 메모리 공간보다 더 많은 공간이 존재하는 것처럼 가장할 수 있다는 것을 알 수 있다.

스왑 공간에만 스왑을 할 수 있는 것은 아니다. 예를 들어, 프로그램을 실행할 때 이 프로그램의 페이지들은 디스크에 존재한다. 프로그램이 실행되면 각 페이지들은 메모리로 탑재된다. (프로그램 실행 시 한 번에 모두 탑재되거나 또는 필요 시 한 페이지씩 탑재할 수 있다.) 물리 메모리에 추가 공간을 확보해야 할 때, 코드 영역의 페이지들이 차지하는 물리 페이지는 즉시 다른 페이지가 사용할 수 있다. 코드가 저장되어 있는 파일 시스템 영역이 스왑 목적으로 사용되는 셈이고 해당 페이지들은 디스크에 원본이 있으므로, 언제든지 다시 스왑 인이 가능하기 때문이다.


Present Bit


디스크에 스왑 공간을 확보했으니 이제 페이지 스왑을 위한 기능을 다룰 차례이다. 하드웨어 기반의 TLB를 사용하는 시스템을 가정하자.

먼저 메모리가 참조되는 과정을 되집어보면,

  1. 프로세스가 가상 메모리 참조를 생성한다.
  2. 하드웨어는 메모리에서 원하는 데이터를 가져오기 전에 가상 주소를 물리 주소로 변환한다.
  3. 하드웨어는 가상 주소에서 VPN을 추출한 후에 TLB에 해당 정보가 있는지 검사한다.
  4. TLB 히트라면 추가적인 메모리 접근 없이 물리 주소를 얻은 후에 매우 빠르게 메모리로 가져온다.
  5. TLB 미스라면 하드웨어는 PTBR를 사용하여 페이지 테이블의 메모리 주소를 파악하고, VPN을 인덱스로 하여 원하는 PTE를 추출한다.
  6. 해당 PTE가 유효하고 관련 페이지가 물리 메모리에 존재하면 하드웨어는 PTE에서 PFN 정보를 추출하고 그 정보를 TLB에 탑재한다.
  7. TLB 탑재 후 명령어를 재실행하여 TLB 히트를 유도한다.

페이지가 디스크로 스왑되는 것을 가능케 하려면, 많은 기법들이 추가되어야 한다. 특히, 하드웨어가 PTE에서 해당 페이지가 물리 메모리에 존재하지 않는다는 것을 표현해야 한다. 하드웨어 또는 운영체제가 Present Bit를 사용하여 각 PTE에 어떤 페이지가 존재하는지를 표현한다.

Present 비트가 1이라면, 물리 메모리에 해당 페이지가 존재한다는 것이고 위에 설명한 대로 동작한다. Present 비트가 0이라면, 물리 메모리에 해당 페이지가 존재하지 않는다는 것이고, 디스크 어딘가에 존재한다는 것을 나타낸다.

물리 메모리에 존재하지 않는 페이지를 접근하는 행위를 일반적으로 페이지 폴트(page fault)라고 한다. 페이지 폴트가 발생하면, 이를 처리하기 위해 운영체제로 제어권이 넘어가 페이지 폴트 핸들러(page fault handler)가 실행된다.


페이지 폴트


TLB 미스의 처리 방법에 따라, 두 종류의 시스템이 있었다. 하등웨어가 페이지 테이블을 검색하여 원하는 변환 정보를 찾는 것인 하드웨어 기반의 TLB와 운영체제가 처리하는 소프트웨어 기반의 TLB이다. 둘 중 어느것이던, 페이지 폴트가 발생하면, 운영체제가 그 처리를 담당한다.

운영체제의 페이지 폴트 핸들러가 그 처리 메커니즘을 규정한다. 거의 대부분의 시스템들에서 페이지 폴트는 소프트웨어적으로 처리되고, 하드웨어 기반의 TLB도 페이지 폴트 처리는 운영체제가 담당한다.

만약 요청된 페이지가 메모리에 없고, 디스크로 스왑되었다면, 운영체제는 해당 페이지를 메모리로 스왑해 온다. 그렇다면 원하는 페이지의 위치를 어떻게 파악할까?

많은 시스템들에서 해당 정보 즉, 해당 페이지의 스왑 공간상에서의 위치를 페이지 테이블에 저장한다. 운영체제는 PFN과 같은 PTE 비트들을 페이지의 디스크 주소를 나타내는 데 사용할 수 있다.

페이지 폴트 발생 시, 운영체제는 페이지 테이블 항목에서 해당 페이지의 디스크 상 위치를 파악하여, 메모리로 탑재한다. 디스크 I/O가 완료가 되면 운영체제는 해당 PTE의 PFN 값을 탑재된 페이지의 메모리 위치로 갱신한다. 이 작업이 완료되면 페이지 폴트를 발생시킨 명령어가 재실행된다. 재실행으로 인해 TLB 미스가 발생될 수 있으나, 미스 처리 과정에서 TLB 값이 갱신된다. (이를 피하기 위해 페이지 폴트 처리시 함께 TLB를 갱신하는 방법도 있다.) 최종적으로, 마지막 재실행 시에 TLB에서 주소 변환 정보를 찾게 되고, 이를 이용하여 물리 주소에서 원하는 데이터나 명령어를 가져온다.

I/O 전송 중에는 해당 프로세스가 차단된(blocked) 상태가 된다는 것을 유의해야 한다. 페이지 폴트 처리 시 운영체제는 다른 프로세스들을 실행할 수 있다. I/O 실행은 매우 시간이 많이 소요되기 때문에 한 프로세스의 I/O 작업(페이지 폴트)과 다른 프로세스의 실행을 중첩(overlap)시키는 것은 멀티 프로그램된 시스템에서 하드웨어를 최대한 효율적으로 사용하는 방법 중 하나다.


메모리에 빈 공간이 없으면?


위 설명에서, 스왑 공간으로부터 페이지를 가져오기 위한 (page-in) 여유 메모리가 충분하다는 것을 가정하였으나 항상 이렇지는 않다. 메모리에 여유 공간이 없거나 거의 다 찼을 수도 있다. 탑재하고자 하는 새로운 페이지들을 위한 공간을 확보하기 위해 하나 또는 그 이상의 페이지들을 먼저 페이지 아웃(page out)하려고 할 수도 있다. 교체(replace) 페이지를 선택하는 것을 페이지 교체 정책(page replacement policy)라고 한다.


페이지 폴트의 처리


img

하드웨어 처리 과정에서 TLB 미스 발생 시, 세 가지 중요한 경우가 있다.

  1. 페이지가 존재하며 유효한 경우, TLB 미스 핸들러가 PTE에서 PFN을 가져와 명령어를 재시도 하여 TLB 히트를 유도한다.
  2. 페이지가 유효하지만 존재하지 않는 경우, 페이지 폴트 핸들러가 반드시 실행된다.
  3. 페이지가 유효하지 않은 경우, 프로그램 버그 등으로 인해 잘못된 주소를 접근하였기에 PTE의 다른 비트는 의미가 없고, 운영체제의 트랩 핸들러에 의해 처리되도록 한다.

img

위 사진은 운영체제가 페이지 폴트를 처리하는 과정이다.

  1. 운영체제는 탑재할 페이지를 위한 물리 프레임을 확보한다.
  2. 만약 여유 프레임이 없다면, 교체 알고리즘을 실행하여 I/O 요청을 통해 스왑 영역에서 페이지를 읽어온다.
  3. 운영체제는 페이지 테이블을 갱신하고 명령어를 재시도하여 TLB 미스가 발생한다.
  4. 또 한 번의 재시도를 할 때 TLB 히트가 되고, 원하는 데이터에 접근할 수 있다.


교체는 실제 언제 일어나는가


지금까지는 메모리에 여유 공간이 고갈된 후에 교체 알고리즘이 작동하는 것처럼 말하였는데, 실제로는 그렇지 않다. 운영체제는 항상 어느 정도의 여유 메모리 공간을 확보하고 있어야 한다.

메모리에 항상 어느 정도 여유 공간을 비워두기 위해서, 대부분의 운영체제들은 여유 공간에 관련된 최댓값(high watermark, HW)최솟값(low watermark, LW)을 설정하여 교체 알고리즘 작동에 활용한다.

동작 방식은 다음과 같다.

  1. 운영체제가 여유 공간의 크기가 최솟값보다 작아지면 여유 공간 확보를 담당하는 백그라운드 쓰레드가 실행된다.
  2. 이 쓰레드는 여유 공간의 크기가 최댓값에 이를 때까지 페이지를 제거한다. (이 백그라운드 쓰레드는 일반적으로 스왑 데몬(swap daemon) 또는 페이지 데몬(page daemon)이라고 불린다.)
  3. 충분한 여유 메모리가 확보되면 이 백그라운드 쓰레드는 Sleep 모드로 들어간다.

동시에 여러 개를 교체하면 성능 개선이 가능하다. 예를 들어 많은 시스템들은 다수의 페이지들을 클러스터(cluster)그룹(group)으로 묶어서 한 번에 스왑 파티션에 저장함으로써 디스크의 효율을 높인다. 클러스터링은 디스크의 탐색(seek)와 회전 지연(rotational delay)에 대한 오버헤드를 경감시켜 성능을 상당히 높일 수 있다.

백그라운드 페이징 쓰레드를 사용하기 위해서는 그림 24.3의 과정이 약간 변경되어야 한다. 교체를 수행하는 대신 알고리즘은 사용할 수 있는 페이지들이 있는지를 단순히 검사만 한다. 만약 없다면 백그라운드 페이징 쓰레드에게 여유 페이지들이 필요하다고 알려준다. 쓰레드는 페이지들을 비운 후에 원래의 쓰레드를 다시 깨워서 원하는 페이지를 불러들일 수 있도록 하며 계속 작업을 진행할 수 있도록 한다.


요약


  • Swapping : 물리 메모리의 한계를 넘어 더 큰 가상 주소 공간을 지원하는 기법. 현재 필요하지 않은 메모리 페이지를 디스크의 스왑 공간으로 보내고 필요 시 다시 메모리로 가져온다.
  • Swap Out : 메모리에서 디스크로 페이지를 보내는 것.
  • Swap In : 디스크에서 메모리로 페이지를 가져오는 것.
  • Swap Space : 물리 메모리에서 잠깐 내려온 페이지들을 저장하기 위해 디스크에 할당된 특정 영역
  • Present Bit : 페이지가 물리 메모리에 존재하는지 여부를 나타내는 PTE의 비트. 1이면 물리 메모리에 존재. 0이면 스왑 공간에 존재.
  • Page Fault : 프로세스가 접근하려는 페이지의 Present Bit가 0일 때 발생하는 하드웨어 트랩. 운영체제에게 제어권을 넘긴다.
  • Page Fault Handler : 페이지 폴트가 발생했을 때 운영체제가 실행하는 코드. 스왑 공간에서 요청된 페이지를 찾아 물리 메모리의 빈 공간으로 가져온 후, 페이지 테이블을 갱신하고 중단되었던 명령어를 다시 실행한다.
  • Page Replacement Policy : 메모리에 여유 공간이 없을 때, 어떤 페이지를 디스크로 스왑 아웃할지 결정하는 알고리즘.
  • Swap Daemon (Page Daemon) : 메모리에 항상 일정량의 여유 공간을 확보하기 위해 백그라운드에서 실행되는 프로세스. 메모리의 여유 공간이 최솟값(Low Watermark) 이하로 떨어지면, 페이지들을 미리 디스크로 내보내 공간을 확보한다.


참고

This post is licensed under CC BY 4.0 by the author.