[PINTOS] project3: Virtual Memory

김승환·2022년 1월 25일
0

SW정글

목록 보기
3/4

지난 2주 동안은 project3을 진행하면서 메모리를 추상화하는 가상 메모리에 대해 알아보고, 메모리를 관리하는 기법인 MMU, 페이징과 TLB 등을 이해해보았다.

물리 및 가상 주소 방식

물리 주소 방식을 사용하는 컴퓨터는 다음과 같은 방식으로 데이터를 읽는다. 물리 주소가 0 ~ M-1까지 존재할 때, CPU가 물리 주소 4에서 4바이트 워드를 읽는다면, CPU는 메모리 버스를 통해 이것을 메인 메모리에 전달하고 메인 메모리는 물리 주소 4에서 시작하는 4바이트 워드를 선입하고 이것을 CPU에 돌려준다.

가상 주소 방식을 사용하는 컴퓨터에서 CPU는 가상주소(VA)를 생성하고 메인 메모리에 접근하며, 가상 주소는 메모리에 접근하기 전에 CPU chip 내의 MMU를 지나 메인 메모리에 보내질 적절한 물리 주소로 변환된다.

캐싱 도구로서의 VM

VM system은 가상메모리를 규정된 사이즈 블록 단위로 분할하여 관리하고, 이 분할된 블록을 가상페이지라 한다. 물리 메모리도 마찬가지로 물리페이지로 분할되어 사용된다. 가상 페이지의 집합은 unallocated, cached, uncached의 부분집합으로 나누어진다.

  • Unallocated: VM 시스템에 의해 아직까지 할당되지 않은 페이지
  • Cached: 현재 물리 메모리에 할당된 페이지
  • Uncached: 물지 메모리에 캐시되지 않은 할당된 페이지

DRAM 캐시의 구성

L1, L2, L3 → SRAM

DRAM 캐시 → 가상페이지를 메인 메모리로 캐싱하는 VM 시스템 캐시

DRAM은 SRAM보다 10배 더 느리고, 디스크보다는 100,000배 더 빠르다. 그러므로, DRAM 캐시 미스는 SRAM 캐시 미스보다는 더 값이 비싸다. 또한 디스크의 첫 바이트를 읽는 비용은 연속적인 바이트를 읽는것보다 100,000배는 느리다. 그렇기때문에 가상페이지는 4KB ~ 2MB 정도로 커지고 있다.

페이지 테이블

모든 캐시에서처럼 VM 시스템은 가상페이지가 DRAM 어딘가에 캐시되었는지 결정하기 위한 방법을 갖고 있어야 한다. 페이지 테이블이 이러한 역할을 담당하며, 페이지 테이블 엔트리(PTE, page table entry)의 배열로 구성된다. PTE가 유효 비트(valid bit)와 n bit의 주소 필드로 구성된다고 가정하자. 유효 비트는 가상 페이지가 현재 DRAM에 캐시되어 있는 지를 나타낸다. 유효 비트가 세팅되었다면(valid bit == 1) 주소 필드는 가상페이지가 캐시되어 대응되는 DRAM의 물리 페이지의 시작을 나타낸다. 만약 세팅되어있지 않다면(valid bit == 0), 가상페이지가 아직 할당되어있지 않는 NULL값 혹은 가상 페이지의 시작 부분을 가르키는 주소값을 가지고 있다.

위의 그림은 page table 1, 2, 4, 7 PTE는 physical memory를 3, 6 PTE는 disk의 가상 메모리를 가르키고 있고 0, 5 PTE는 할당되어 있지 않음을 의미한다.

Page Hits

CPU가 DRAM에 캐시되어 있는 가상메모리의 VP2 워드를 한개 읽을 때, 주소 번역 하드웨어(address translation hardware)는 가상 주소를 인덱스로 사용하여 PTE2를 찾고, 이것을 메모리에서 읽는다. 유효 비트가 세트되어 있기 때문에 VP 2가 메모리에 캐시되어 있음을 의미하고, PTE 내의 물리 메모리 주소를 사용해서 물리 메모리의 데이터에 접근한다.

Page Fault

만약 CPU가 VP3의 시작 비트에 접근하려고 할때, 미스가 발생하는데 이를 page fault라고 한다. 주소 번역 하드웨어는 메모리로부터 PTE3을 읽고, 유효 비트가 unvalid(0)임을 확인하고 page fault를 유발한다. page fault exception이 발생하면 물리 메모리에 올라가 있는 페이지중 희생할 페이지 하나를 선택한다. 만약 VP4를 희생 페이지로 정했다고 하자, VP4가 수정되었다면 데이터를 디스크에 복사하고 PTE4의 유효 비트를 0으로 바꾼다. 그 후 VP3를 디스크에서 물리 메모리에 올린다. 이때 페이지가 디스크에서 DRAM으로 옮겨지는 것을 swap in, DRAM에서 디스크로 옮겨지는 것은 swap out이라 한다.

Allocating Page

위에 예제에서 VP5는 공간이 할당되어 있지 않은 상태이다. 이때 malloc과 같은 함수로 디스크상에 VP5를 위한 공간을 만들고 PTE5를 새롭게 만든 페이지를 가르키도록하면 페이지가 할당된다고 한다.

메모리 관리를 위한 도구로서의 VM

실제 운영체제는 각 프로세스마다 별도의 페이지 테이블을 제공하며, 별도의 가상 주소공간을 제공한다. 그 과정에서 다수의 가상페이지들이 동일한 공유된 물리페이지에 매핑될 수 있다. demend page와 virtual address space의 조합은 메모리가 시스템에서 사용되고 관리되는 방식에 중요한 영향을 준다. 특히 VM은 링킹, 로딩, 코드와 데이터 공유, application에 메모리 할당들을 단순화한다.

  • 링킹 단순화: 별도의 주소공간은 각 프로세스들이 각 메모리 이미지에 대해서 코드와 데이터가 실제로 물리 메모리 내 어디에 위치하는지에 상관없이 동일한 기본 형식을 사용하도록 해준다.
  • 로딩 단순화: 가상메모리는 실행파일과 공유 목적파일들을 메모리에 로드하기 쉽게 해준다. how? 리눅스 로더의 경우 코드와 데티어 세그먼트를 위한 가상의 페이지를 할당하고, 이들을 무효로 표시하고(= 캐시되지 않은 상태), 이들의 페이지 테이블 엔트리를 목적파일의 해당 위치를 가리키게 한다. 이때 로더는 실제로 디스크로부터 메모리로 데이터를 복사한 것이 아니다. 메모리 매핑을 통해 가상 페이지를 임의의 파일 내의 임의의 위치로 매핑한다.
  • 공유 단순화: 별로의 주소공간은 운영체제에 사용자 프로세스와 운영체제 자신 사이에 공유를 관리하는 일정한 메커니즘을 제공한다. 일반적으로 각 프로세스는 다른 프로세스와 공유되지 않은 자신만의 영역을 가지고, 이 경우 운영체제는 대응되는 가상페이지를 중첩되지 않는 물리페이지로 매핑하는 페이지 테이블을 만든다. 그러나 printf같은 표준 c 라이브러리 코드는 각 프로세스에 별로도 포함되는 것 보다는 각 프로세스의 가상페이지들이 물리페이지를 가르키게하는 것이 유리하다.
  • 메모리 할당 단순화: 가상메모리는 추가적인 메모리를 사용자 프로세스에 할당하기 위한 간단한 메커니즘을 제공한다. 프로그램이 추가적인 힙 공간을 요청하면, 연속적인 가상메모리 페에지를 할당하고 연속적인 물리 메모리 영역을 찾을 필요없이 물리 메모리 내에 랜덤하게 흩어져있는 페이지들을 할당할 수 있다.

물리 메모리 보호를 위한 도구로서의 VM

모든 현대 컴퓨터 시스템은 운영체제가 메모리 시스템에 접근하는 것을 제어할 수 있는 수단을 제공한다. PTE에 허가 비트를 추가해서 주소 변역 하드웨어가 가상페이지 내용으로의 접근을 제어하는 방식을 사용한다. 예를 들어, kernel mode인지 user mode인지를 파악하는 SUP비트나, 페이지에 대한 읽기와 쓰기가 가능한지 파악하는 READ, WRITE 비트를 추가하여 프로세스의 페이지 제어 가능 여부를 파악한다.

주소의 번역

주소 번역은 N-원소 가상 주소공간(VAS, virtual address space)와 M-원소 물리 주소공간(PAS, physical address space)의 원소들 간의 매핑이다.

위 그림은 MMU가 매핑을 하기 위해 페이지 테이블을 어떻게 사용하는지를 보여준다. CPU 내에 있는 제어 레지스터인 페이지 테이블 베이스 레지스터(Page table base register)는 현재 페이지 테이블의 시작 지점을 가리킨다. n 비트 가상 주소는 p 비트 가상 페이지 오프셋(VPO, virtua; page offset)과 (n - p) 비트 가상페이지 번호(VPN, virtual page number)를 가진다. MMU는 VPN을 사용해서 적합한 PTE를 선택한다. 대응되는 물리 주소는 페이지 테이블 엔트리에서 가져온 물리페이지 번호(PPN, physical page number)와 VPO를 연결한 것이다. 이때 PPO과 VPO는 동일한 p 바이트이므로 둘은 동일하다.

위 그림은 page hit가 발생했을 때 CPU 하드웨어가 수행하는 단계를 보여준다.

  1. 프로세서는 가상주소를 생성하고 이것을 MMU로 보낸다.
  2. MMU는 PTE 주소를 생성하고 이것을 캐시/메인 메모리에 요청한다.
  3. 캐시/메인 메모리는 PTE를 MMU로 리턴한다.
  4. MMU는 물리 주소를 구성하고 이것을 캐시/메인 메모리로 보낸다.
  5. 캐시/메인 메모리는 요청한 데이터 워드를 프로세서로 보낸다.

위 그림은 page fault가 발생했을 경우 하드웨어와 운영체제 커널이 수행하는 단계를 보여준다.

  1. 프로세서는 가상주소를 생성하고 이것을 MMU로 보낸다.
  2. MMU는 PTE 주소를 생성하고 이것을 캐시/메인 메모리에 요청한다.
  3. 캐시/메인 메모리는 PTE를 MMU로 리턴한다.
  4. PTE 유효비트는 0이므로 MMU는 예외를 발생시키고, CPU 내의 제어를 운영체제 커널의 page fault exception handler로 이동시킨다.
  5. fault handler는 물리 메모리 내의 희생 페이지를 결정하고, 만일 희생 페이지가 수정되었다면 디스크로 페이지를 이동한다.
  6. fault handler는 새 페이지를 페이지 이동해서 들여오고, 메모리 내의 PTE를 갱신한다.
  7. fault handler는 처음의 프로세스로 돌아가고, faulting instruction은 다시 수행된다. 즉, CPU는 동일한 가상 주소를 다시 MMU로 전송하게 된다. 하지만 이전과는 다르게 가상 주소에 대응하는 물리 메모리 주소가 캐싱되어 있으므로 page hit가 발생하고 메인 메모리는 요청한 워드를 프로세서로 넘겨준다.

TLB를 사용한 주소 번역 속도의 개선

TLB(translation lookaside buffer)는 작은 가상주소지정 캐시로, 각 라인은 하나의 PTE로 구성된 하나의 블록을 저장한다. 만약 TLB가 2^t개의 집합을 가진다면, TLB index는 t개의 최소 중요 비트로 구성되고, VPN의 나머지 비트로 이루어진 TLB tag로 구성된다.


위의 그림은 TLB hit가 발생했을 때 수행되는 단계를 보여준다.

  1. CPU는 가상주소를 생성한다.
  2. MMU는 VPN을 TLB로 보낸다.
  3. MMU는 TLB로부터 적당한 PTE를 가져온다.
  4. MMU는 가상 주소를 물리 주소로 번역하고, 그것을 캐시/메인 메모리로 전송한다.
  5. 캐시/메인 메모리는 요청한 데이터 워드를 CPU로 리턴한다.

TLB miss가 발생하면, 위에 단계에서 MMU는 PTE를 L1 캐시에서 가져와 TLB에 저장하는 과정이 추가된다.

다중 레벨 페이지 테이블

지금까지는 시스템이 주소를 번역하기 위해서 한 개의 페이지 테이블을 사용한다고 가정해왔다. 그러나 32비트 주소공간, 4KB 페이지, 4바이트 PTE인 경우, application이 작은 크기의 가상 주소공간만 참조하는 경우에도 메모리에 항상 4MB 페이지 테이블을 필요로하게 된다.

4바이트 페이지 테이블 엔트리를 갖는 4 KB 페이지로 나누어진 32비트 가상 주소공간에 대해 생각해보자. 또한 이 시점에서 가상 주소공간이 위의 그림과 같이 2K 메모리 페이지는 코드와 데이터에 할당되고, 다음 6K 페이지는 미할당 상태이며, 다음 1023개의 페이지들 또한 미할당 상태, 다음 페이지는 사용자 스택에 할당되었다.

1단계 테이블의 각 PTE는 4M의 가상 주소 공간 크기를 매핑하는 역할을 하며, 이들 각각의 블록은 2^10개의 연속적인 페이지들로 구성된다. 예를 들어, PTE 0는 첫 번째 블록을, PTE 1은 다음 블록을 맵핑한다. 만약 chuck i 안의 모든 페이지들이 할당되지 않았다면 level 1 PTE i 는 null이다. 그러나 만약 하나의 페이지라도 할당되었다면, level 1 PTE i 는 level 2 페이지 테이블의 베이스를 가르킨다. 예를 들어, 블록 0, 1, 8의 일 부분이 할당되었고, 이들의 1단계 PTE는 2단계 페이지 테이블을 가리킨다.

2단계 페이지 테이블 내의 각 PTE들은 4KB 가상메모리 페이지를 관리하며, 이것은 앞에서 단일 레벨 페이지 테이블을 살펴보았을 때와 동일하다.

이 기법은 메모리 요구량을 두 가지 방법으로 줄여준다. 첫째는 만일 1단계 테이블의 PTE가 null이면, 해당 2단계 페이지 테이블이 존재할 필요가 없어진다. 둘째는 1단계 테이블만이 항상 메인 메모리에 있을 필요가 있다는 것이다. 2단계 페이지 테이블은 이들이 필요할 때 VM 시스템에 의해서 생성되고, 페이지 인 또는 아웃될 수 있으며, 이로 인해 메인 메모리로의 압박을 줄일 수 있다.

멀티 레벨 페이징을 이용하는 것은 비실용적이고 값비싼 것처럼 보일지 모르지만, TLB 덕분에 단일 레벨 페이지 테이블을 이용하는 것에 비해 많이 느려지는 편은 아니다.

메모리 매핑

리눅스는 가상메모리 영역의 내용을 디스크의 객체에 연결해서 초기화한다. 이 과정은 메모리 매핑이라고 알려져 잇으며 두 종류의 객체 중의 하나로 매핑될 수 있다.

  • 리눅스 파일 시스템 내의 regular file: 한 영역은 실행가능 목적파일과 같은 일반 디스크 파일의 연속적인 섹션으로 매핑될 수 있다. 파일 섹션은 페이지 크기의 조각들로 나누어지고, 이들은 각각 가상페이지의 초기 내용을 포함하고 있다.
  • Anonymous file: 한 영역은 커널에서 만들어진 모두 이진수 0으로 적힌 anonymous file로 매핑될 수 있다. CPU가 이 영역의 가상페이지에 처음으로 접근할 때, 커널은 물리 메모리 내에서 적당한 희생 페이지를 찾고, 이것이 dirty하다면 희생 페이지를 스왑 아웃하고, 희생 페이지를 이진수 0 으로 덮어쓰고, 페이지 테이블을 갱신한다. 어떤 데이터도 실제로는 디스크와 메모리 사이에 이동하지 않는다. 이 이유 때문에 무기명 파일로 매핑된 영역 내의 페이지들은 때로는 demand-zero 페이지라고 불린다.

어떤 경우 던지 일단 초기화가 되었다면 커널이 관리하는 swap file(swap space or swap area) 사이에서 swap-in or swap-out되며 관리가 된다.

profile
팀스파르타에서 IT 직군 채용 플랫폼 '인텔리픽'을 개발하고 있습니다.

0개의 댓글