21. 가상 메모리와 디맨드 페이징: Chapter 10. Virtual Memory (Part 1)

HotFried·2023년 10월 24일

10.1 Background (배경)

지금까지 살펴본 메모리 관리 기법은 명령어가 반드시 물리적 메모리에서 실행되어야 한다는 필요에 의해 사용되었다.

실제로 거의 사용되지 않는 코드가 실행되거나 & 자료구조가 실제 필요한 양보다 더 많은 메모리를 할당받는 것은 비효율적이다.

따라서, 프로그램의 일부만 실제 메모리를 할당하여 실행한다.

  • Virtual Memory(가상메모리) 실제 물리 메모리 개념과 개발자의 논리 메모리 개념을 분리한 것 → 작은 메모리를 가지고 얼마든지 큰 가상 주소 공간 제공 가능

  • Virtual Adress Space (가상 주소 공간)
    한 프로세스의 가상 주소 공간은 그 프로세스가 메모리에 저장되는 논리적인(가상적인) 모습
    • 위 그림과 같이 특정 논리 주소는 0번지에서 시작하여 연속적인 공간을 차지
    • Heap은 동적 메모리를 사용함에 따라 주소 공간 상에서 위쪽으로 확장
    • Stack은 함수 호출을 거듭함에 따라 주소 공간 상에서 아래쪽으로 확장
    • Heap와 Stack 사이의 공간은 논리적 주소 공간으로는 존재하지만, 실제 물리적 페이지를 필요로 하는 순간은 오직 Heap과 Stack이 그만큼 커졌을 때이다.

  • 가상 메모리를 통한 라이브러리의 공유

논리 메모리를 물리 메모리로부터 분리해주는 것 외에 가상 메모리는 페이지 공유를 통해 파일이나 메모리가 둘 또는 그 이상의 프로세스들에 의해 공유되는 것을 가능하게 한다.


10.2 Demand Paging (요구 페이징)

  • 실행 프로그램을 보조 저장장치에서 메모리로 적재하는 방법
    1. 프로그램 실행 시작 시 프로그램 전부를 물리 메모리에 적재하는 기법
      • 초기에는 프로그램의 전체가 메모리에 있을 필요가 없다
    2. demand paging: 필요한 페이지만 적재하는 기법
      • 프로그램 실행 중 필요할 때만 페이지 적재
      • 따라서 접근 되지 않은 페이지는 물리 메모리로 적재되지 않는다

10.2.1 Basic Concepts (기본 개념)

  • 요구 페이징은 결과적으로 프로세스가 실행되는 동안 일부는 메모리에 있고, 일부는 보조 저장 장치에 있다. → 따라서 이 둘을 구분하기 위해 하드웨어 지원이 필요하다.

  • 유효Valid/무효 기법Invalid 기법이 여기에 적용될 수 있다.
    1. 비트가 유효하다고 설정되면 해당 페이지가 메모리에 있다는 것을 의미
    2. 비트가 무효하다고 설정되면 해당 페이지가 유효하지 않거나(가상 주소 공간상에 정의되지 않거나), 유효하지만 보조 저장장치에 있다는 것을 의미

페이지에 Invalid를 표시하는 것은 프로세스가 해당 페이지에 아예 접근하지 않는다면 효과가 없다.

→ 언젠가 접근한다면 몰라도, 아예 접근을 안 한다면 없는 것과 마찬가지다.


  • Page Faults (페이지 폴트) 프로세스가 메모리에 올라와 있지 않은 페이지에 접근하려고 하면 페이지 폴트이 발생한다.

  • 페이지 폴트를 처리하는 과정

    1. 페이지 결함이 발생하면 운영체제에 페이지 결함 트랩(Page Fault Trap)을 발생시킨다. (그림의 2번에 해당한다.)

    2. PCB에 존재하는 내부 테이블을 통해 참조의 유효성을 검사한다. 만약 프로세스의 가상 주소 공간을 벗어난 참조(무효)라면 프로세스는 종료된다. (그림의 3번에 해당한다.)

    3. 사용 가능한 빈 프레임을 찾아 디스크 입출력을 통해 페이지를 프레임에 적재한다. (그림의 4번에 해당)

    4. PCB의 내부 테이블과 페이지 테이블을 메모리에 적재된 페이지를 가리키도록 수정한다. (그림의 5번에 해당)

    5. 페이지 결함 트랩을 발생시켰던 명령어를 재실행한다. (그림의 6번에 해당)


  • Pure Demand Paging (순수 요구 페이징)

    극단적으로 메모리의 페이지를 하나도 가지지 않은 상태로도 프로세스를 실행(어떤 페이지가 필요해지기 전까지는 결코 그 페이지를 메모리로 적재하지 않는다)

    이 방법은 프로세스 실행 초기에 많은 페이지 결함을 발생한다.
    → BUT, 시스템 성능의 저하를 초래하지는 않는다.(참조의 지역성 때문)


  • Locality of Reference (참조의 지역성)

    프로세스가 실행될 때 항상 어떤 특정한 지역에서만 메모리를 집중적으로 참조하는 것


요구 페이징을 지원하기 위해서는 페이지 폴트 오류 처리 후 명령어 처리를 다시 시작할 수 있어야 한다.

즉, 페이지 폴트가 발생하여 중단된 프로세스 상태(레지스터들)를 보관해두면 다시 이 프로세스를 시작할 때 정확히 같은 위치, 같은 상태에서 프로세스를 다시 수행할 수 있어야 한다.

하지만 어떤 명령어가 여러 다른 위치를 수정할 수 있다면 꽤 큰 문제가 된다. 한 명령어가 둘 이상의 다른 페이지에 접근하는 경우에는 그 명령어를 간단히 다시 실행할 수 없을 수도 있다. 이러한 문제는 두 가지 방법으로 해결될 수 있다.

  • 명령어 수행에 필요한 모든 페이지를 미리 메인 메모리에 적재한 다음 명령어를 다시 수행한다.
  • 임시 레지스터를 이용해 갱신 전의 값을 저장해둔 후, 페이지 결함이 발생했을 때 이전 값을 다시 원래 위치에 쓴다.

10.2.2 Free-Frame List (가용 프레임 리스트)

  • 페이지 폴트가 발생하면 운영체제는 요청된 페이지를 보조 저장장치에서 메인 메모리로 가져와야 한다.

  • 페이지 폴트를 해결하기 위해 대부분의 운영체제는 이러한 요청을 충족시키기 위해 사용하기 위한 가용 프레임의 풀인 가용 프레임 리스트를 유지한다.

  • 프로세스의 스택, 힙 등이 확장될 때도 가용 프레임이 할당되어야 한다.


10.2.3 Performance of Demand Paging (요구 페이징의 성능)

만약 페이지 결함이 발생하지 않는다면, 유효 접근 시간은 이 메모리 접근 시간과 같을 것이다.

하지만 페이지 결함이 발생한다면, 관련된 페이지를 디스크에서 읽은 후에야 원하는 동작이 가능할 것이다.

  • 유효 접근 시간
    p : 페이지 결함이 발생할 확률 (0~1)
    ma : 메모리 접근시간

    effectiveeffective accessaccess timetime = (1p)ma(1-p) * ma + pp * pagepage faultfault timetime

10.3 Copy-on-Write (쓰기 시 복사)

  • fork()를 통해 생성되는 프로세스들은 이러한 요구 페이징 과정을 페이지 공유와 유사한 방법을 사용할 수 있다.
  1. 자식 프로세스가 시작할 때 부모의 페이지를 당분간 함께 사용한다.
  2. 자식 프로세스가 페이지를 수정할 경우 가상 메모리를 복사하여 수정한 새로운 페이지를 가리킨다.

(수정이 일어날 때 해당 페이지만 복사해서 별도로 이용)


참고 :

Silberschatz et al. 『Operating System Concepts』. WILEY, 2020.

주니온TV@Youtube: 자세히 보면 유익한 코딩 채널

profile
꾸준하게

0개의 댓글