본문으로 바로가기

[운영체제(OS)] 가상메모리

category Computer Science/OS 2021. 7. 13. 16:05

가상 메모리

가상 메모리 메모리 관리 기법의 하나로, 한정된 물리 메모리 자원을 추상화하여 사용자들에게 큰 (주) 메모리로 보이게 만드는 것을 말한다. 각 프로그램 들은 실제 메모리 주소가 아닌 가상의 메모리 주소를 사용하게 된다.

가상 메모리가 필요한 이유

만약 가상메모리를 사용하지 않고 물리 메모리만 사용한다면 다음과 같은 문제들이 발생. 이를 해결하기 위해 가상 메모리를 사용한다.

  • 물리적인 메모리 공간 부족.
  • 메모리 단편화 문제 발생.
  • 다른 프로세스의 메모리 영역 접근 문제.

위 문제를 구체적으로 살펴보면 다음과 같다.

물리적인 메모리 공간의 부족 문제

하나의 프로세스는 일반적으로 4GB의 메모리 공간을 요구함.(32bit 기준) 때문에 여러 프로세스가 동시에 처리되는 일반적인 운영체제에서 하나의 프로세스에 물리적인 4GB 메모리를 할당하기에는 한계가 있음. 이를 보완하기 위해 가상 메모리가 사용됨. (배치 처리 시스템에는 필요 없음.)

 

메모리 단편화 문제

위 그림을 살펴보면 100 바이트씩 총 200 바이트의 빈 공간이 있지만 2개의 영역으로 단편화 되어있기 때문에 200 바이트 크기의 프로세스를 할당할 수 없는 문제가 발생. 각 프로세스는 동적으로 메모리를 추가 할당 및 해제할 뿐만 아니라, 새로운 프로세스가 언제 생겨서 사라질 것인지 예측할 수 없기 때문에 메모리 단편화 문제는 항상 발생할 수밖에 없음.

 

다른 프로세스의 메모리 영역 접근 문제

만약 물리 메모리 주소만 활용한다면, 임의의 프로세스에서 다른 프로세스에서 활용중인 물리 메모리 주소를 지정하여 접근할 수 있게 된다. 그리고 그 주소가 커널 영역이라면 전체 시스템에 큰 위협이 된다.

 

가상 메모리의 이해

위 문제를 해결하기 위해서 OS는 프로세스가 생성될 때 각 프로세스에게 가상의(논리적인) 연속된 메모리 공간(32비트 기준 4GB)인 가상메모리를 제공해 주고, 프로세스가 이 가상 주소에 접근하려고 할 때 OS는 가상 주소를 물리 주소로 변환하여 물리주소에 저장된 값을 프로세스에 반환하는 방식으로 동작한다. 이때 빠른 변환을 위해서 변환을 전담하는 하드웨어인 MMU를 사용한다.

  • 가상 주소(Virtual address): 프로세스가 참조하는 주소
  • 물리 주소(Physical address): 실제 메모리 주소
  • MMU(Memory Management Unit): CPU에서 가상 주소에 접근할 때, 해당 주소를 물리 주소 값으로 변환해주는 하드웨어 장치.

▲ MMU의 역할

페이징 시스템

실제 물리 공간에 데이터를 로드할 때 로드되는 데이터의 단위 크기를 페이지(Page)라고 한다. 리눅스에서는 4KB 단위로 페이징 한다. 그밖에 Intel x86 시스템은 4KB, 2MB, 1GB 단위를 지원한다.

가상 주소 구조

가상 주소는 페이지 번호와 그 페이지 안에서 데이터의 변위로 이루어져 있다.

  • 가상 주소 V = (p, d)
    • p: 페이지 번호
    • d: p 안에서 데이터의 위치(변위 or 오프셋)

리눅스에서 사용하는 32bit 주소, 4KB 단위의 페이징 시스템에서는 상위 20bit가 페이지 번호, 하위 12bit가 데이터의 위치(변위)가 된다.

  • 하위 12bit \((2^{12} =4,096)\) 로 4KB를 표현할 수 있다.
  • 상위 20bit \((2^{20} =1,048,576)\) 만큼의 페이지가 존재한다.

페이지 테이블

물리 주소에 있는 페이지 번호와 해당 페이지의 첫 물리 주소 정보를 매핑한 표이다. 프로세스 PCB에는 페이지 테이블을 가리키는 주소가 들어있다. 이를 통해서 페이지 테이블에 접근할 수 있다.

▲ 페이지 테이블

해당 프로세스에서 특정 가상 주소(v = p+d)를 참조하기 위해서는 아래와 같이 동작한다.

  • 해당 프로세스의 페이지 테이블에 해당 가상 주소의 페이지가 있는지 확인
  • 페이지 테이블에 해당 가상 주소의 페이지가 있다면, 페이지에 매핑된 첫 물리 주소 p'를 알아낸다.
  • 해당 가상 주소의 실제 주소는 p' + d가 된다.

다중 단계 페이징 시스템

간단한 프로그램 같은 경우 사용하는 메모리의 크기가 작을 수 있다. 간단한 C언어 코드의 메모리 사용량은 10KB보다도 작을 수 있다. 이런 경우에 모든 페이지에 대한 정보를 페이지 테이블에 저장하는 것은 시간과 공간이 낭비된다. 그래서 페이지를 디렉터리로 나눠서 하나의 디렉터리에 하나의 페이지 테이블을 갖게 하고, 사용되는 디렉터리의 페이지 테이블만 메모리에 로드하는 방식을 다중 단계 페이징 시스템이라 한다.

▲ 페이지 디렉토리 구조

페이지 정보 캐시(TLB)

MMU가 실제 물리 주소를 알아내게 위해서는 페이지 테이블을 참조해야 한다. 그런데 CPU에서 가상 테이블 주소를 요청받을 때마다 페이지 테이블을 참조하게 될 경우 똑같은 반복 작업을 여러 번 하는 문제가 발생한다. 이 부분을 TLB(Translation Lookaside Buffer - 페이지 정보 캐시)로 개선하였다. 캐시에 접근하는 것은 메모리에 접근하는 것보다 수십 배의 성능 향상 효과를 볼 수 있기 때문이다.

▲ 하드웨어 장치별 접근시간

TLB를 사용할 경우 아래와 같은 구조로 페이징 시스템을 구성할 수 있다.

▲ TLB 구조

  1. CPU가 가상 주소로 MMU에 데이터를 요청한다.
    1. MMU가 TLB에 가상 주소의 해당하는 페이지 테이블이 있는지 참조한다.
    2. 있다면 TLB에서 페이지 테이블을 참조한다.
  2. TLB에 캐시된 페이지 테이블이 없다면 메모리의 페이지 테이블을 참조 후 캐싱한다.
  3. 메모리로 부터 물리 주소를 전달 받는다. 
  4. 페이지 테이블을 참조한 후 물리 메모리 주소에 접근한다.
  5. Data값을 CPU에 전달한다.

페이징 시스템과 공유 메모리

프로세스 간 동일한 물리 주소를 가리킬 수 있고 이를 공유 메모리라 한다. 프로세스가 생성될 때마다 모든 메모리를 새롭게 만든다면 굉장한 시간과 공간의 낭비가 발생될 수 있다. 하나의 물리 메모리를 복수개의 프로세스가 사용함으로써 시간과 공간을 절약할 수 있다. 공유메모리로 사용되는 영역은 아래와 같다.

  • 커널 영역
  • 읽기만 가능한 메모리 영역

만약 물리 주소에 데이터 수정 시도 시 이때 물리 주소를 복사하여 별도의 공간을 할당하기도 한다.

요구 페이징

가상 메모리는 프로세스에서 필요한 페이지를 일부만 물리 메모리에 올리고 사용하기 때문에 어떤 페이지를 언제 물리 메모리에 적재할지 결정하는 정책이 필요하다.

  • 선행 페이징: 미리 프로세스 관련 모든 데이터를 메모리에 올려놓고 실행
  • 요구 페이징: 모든 데이터를 메모리로 적재하지 않고, 실행 중 필요한 시점에서 필요한 페이지만 메모리로 적재(Lazy allocation). 더 이상 필요하지 않은 페이지 프레임은 다시 저장매체에 저장.

페이지 폴트

  • 어떤 페이지가 실제 물리 메모리에 없을 때 일어나는 인터럽트
  • 운영체제가 page fault가 일어나면, 해당 페이지를 물리 메모리에 올림
  • 페이지 폴트가 자주 발생하면 저장매체의 입출력이 빈번하여 시간이 오래 걸린다. → 적절한 페이지 교체 정책이 필요하다.

페이지 교체 (스왑)

운영체제가 특정 페이지를 물리 메모리에 올리려 할 때 물리 메모리가 다 차있다면, 저장 장치의 일부를 다음과 같이 일시적으로 메모리 대신 사용한다. 

  • 물리 메모리 부족 현상(OOM) 발생
  • 물리 메모리에서 기존 페이지 중 하나를 저장 장치에 임시로 내림
  • 새로운 페이지를 해당 물리 메모리 공간으로 가져옴

페이지 교체 정책

이때 어떤 페이지를 내릴지 선택하는 것이 중요하고, 이를 페이지 교체 정책이라 한다.

  • OPT(OPTimal Replacement Algorithm): 앞으로 가장 오랫동안 사용하지 않을 페이지를 내린다. 가장 이상적이지만, 현실적으로 구현 불가능함.
  • FIFO: 가장 먼저 들어온 페이지를 내린다. 가장 먼저 들어온 페이지이지만 가장 자주 사용될 수도 있는 문제가 있다.
  • LRU(Least Recently Used): 가장 오래전에 사용된 페이지를 교체한다.
  • LFU(Least Frequently Used): 가장 적게 사용된 페이지를 내린다.
  • NUR(Not Used Recently): 최근에 사용하지 않은 페이지부터 교체한다. 단 각 페이지마다 참조 비트(R), 수정 비트(M)를 두고(R, M)을 기준으로 판단한다. (0,0), (0,1), (1,0), (1,1) 순으로 페이지를 교체한다.

스레싱(Thrashing)

  • 빈번한 페이지 폴트로 인해 과도한 페이지 교체 작업이 일어나 실제로는 아무런 작업을 하지 못하는 상황을 스레싱이라 한다.

세그멘테이션 기법

  • 페이징 시스템과 다르게 가상 메모리를 서로 크기가 다른 논리적 단위인 세그먼트로 분할하는 기법
  • 세그먼테이션 기법에서도 페이징 시스템과 같은 방식의 가상 주소를 사용하고, 세그먼트 테이블을 통해서 물리 주소에 접근한다.
    • v = (s, d) → s는 세그먼트 번호, d는 블록 내 세그먼트의 변위
  • 세그멘테이션과 페이징 시스템은 모두 하드웨어의 지원이 필요한다. 다양한 컴퓨터 시스템에 이식성을 중요시하는 리눅스는 페이징 기법으로만 구현되어 있다. (일부 CPU가 세그멘테이션을 지원하지 않기 때문)

세그멘테이션 기법과 페이징 기법의 차이

▲ 세그멘테이션 vs 페이징

  • 페이징 기법은 내부 단편화
    • 내부 단편화란 9KB 메모리를 사용하기 위해서는 4KB + 4KB + 4KB 페이지가 필요하면서 3KB가 내부적으로 불필요하게 할당되는 문제 발생
  • 세그멘테이션 기법은 외부 단편화
    • 각 세그멘테이션들의 크기가 다르기 때문에 물리 메모리가 원하는 연속된 메모리를 제공해주지 못하는 문제가 발생할 수 있다.

최근에는 성능 문제로 대부분 페이징 기법만 사용하는 추세

 


출처: 

패스트 캠퍼스 운영체제 강의(강사: 이준희)

위키백과: https://ko.wikipedia.org/wiki/가상_메모리 

실습과 그림으로 배우는 리눅스 구조(저자: 다케우치 사토루)