OS의 가상 메모리에 대한 첨언

가상 메모리 체계에 대한 설명이 부족한 것 같아서, 짧게 설명.

현존하는 주요 OS에서 우리가 일반적으로 사용하는 영역 – 부팅 시간이라거나 특정한 OS라거나 등등을 제외한 곳 – 에서는 언제나 가상 메모리를 쓰고 있다. 가상메모리란 개념은 사실 “가상 주소” 때문에 존재하게 되는 개념인데 저 가상 주소는 프로그래밍의 편의를 위해서 있게 된다. OS에서 물리 메모리를 각 응용 프로그램(혹은 OS자체)에 할당해서 사용할 수 있게 해주는데, 이런 가상 주소/가상 메모리 체계를 사용하면

  • 프로그래머가 실제로 해당 주소가 물리 메모리에 있는지 신경쓰지 않아도 되고
  • 하드 디스크 스왑핑을 OS에서 해줄 수 있게 되고
  • OS가 부가적인 보안 기능1이나 보호 기능2을 수행

하는 등의 장점들이 생긴다. 다만 단순히 연속 주소를 제공하려는 목적으로 만드는 가상 메모리 체계의 경우 하드디스크 스왑핑이 없을 수도 있다. 반대로 하드디스크 스왑핑을 구현하는 방법이 가상 메모리만 있는 것도 아니다.3

물리 메모리와 하드디스크 스왑핑을 구현하려고 하면 생기는 문제.

  1. 프로그램 A에서 하드 디스크 스왑핑을 하는데, 메모리 주소 0x1000 2000 ~ 0x1000 2999 까지를 하드디스크로 보냈다고 하자(4 kbytes공간).
  2. 근데 이 부분이 다시 필요해져서 메모리에 올리는데 저 주소는 “다른 프로그램"이 사용하고 있다고 하면 A는 더 이상 진행이 안되게 된다.

이걸 어떻게 해결했느냐? 대충 두가지 해법이 있다.

우선 세그멘테이션 기반. 일명 재배치가능한 코드;relocatable code 라는 것을 사용한다. 해당 프로그램에서 참조하는 모든 주소를 “어떤 기반 주소(시작 주소?);base address + 오프셋;offset"의 형태로 사용하는 것이다. 그리고 메모리 할당은 기반 주소 + 길이의 형태로 해준다. 그러면 0x1000 6000으로 시작되는 메모리 블럭에 다시 올려놓는다고 해도 주소를 저런 “절대 주소"로 참고하는게 아니라 0x 1000 2000 + offset 으로 쓰던거에서 0x 1000 2000에 해당하는 부분을 다른 주소(0x 1000 6000)으로 바꿔주면 OK. 물론 이런 메모리 <-> 하드디스크 스왑핑을 하려면 하드 디스크에 빈 공간이 있어야 한다.4

그리고 페이지 기반의 시스템이 있는데. 메모리를 페이지라는 고정 길이 영역으로 쪼개고, 해당 페이지 주소는 어떤 고정길이의 배수인(보통 4K) 시작 주소 + 오프셋이 된다. 다만 오프셋의 크기가 4K – 1까지 가능한 것으로 고정. 그리고 이 고정 길이 단위로 하드 디스크로 옮겨가거나 다시 메모리로 불러들이거나 한다.

다만 이런 주소 계산을 OS가 소프트웨어적으로 하면 메모리 참조할 때마다 시간이 추가되기 때문에 하드웨어적인 메모리 주소 계산을 사용한다(이런 일을 담당하는 memory management unit;MMU 란 부분이 있다). 그리고 한 번 해본 주소 변환은 주소 변환 참조 테이블;translation lookaside table(TLB) 라는 곳을 이용해서 캐슁;caching 해서 빠르게 변환될 수 있게 한다. (여담이지만 이런 MMU가 없는 CPU에 linux 같이 가상 메모리를 가정하는 OS를 포팅하려면 저 작업을 일일이 수행하는 함수들을 만들어야한다)


References

  • D Bovet and M. Cesati. Understanding the LINUX kernel, 3rd ed.
  • A. Silverchatz, P. Galvin and G. Gagne. Applied Operating System Concepts. 1st ed.

  1. 특정 프로그램이 다른 메모리를 봐도 되는지 여부 등. ↩︎

  2. 특정 메모리 공간을 읽거나/쓰거나/실행해도 되는지 확인. ↩︎

  3. 도스 시절에 overlaying 이란 걸 들어본 사람들이 있을지도. ↩︎

  4. 그런 이유에서 BSD류의 /swap 파일 시스템의 크기는 메모리 용량이 2배로 설정한다. ↩︎