운영체제 공룡책

[운영체제 공룡책] 10장 가상 메모리

studyingalone 2025. 3. 18. 14:21

10.1 Background

 

  • 프로그램을 실행하려면 명령어가 물리 메모리에 있어야 하지만, 물리 메모리의 크기는 제한적이다.
  • 프로그램 전체가 항상 필요하지는 않으며, 오류 처리 코드나 필요 이상으로 할당된 배열 등은 거의 사용되지 않는다.
  • 프로그램의 일부만 메모리에 로드하여 실행할 수 있다면, 더 많은 프로그램을 동시에 실행할 수 있고, 성능도 향상될 것이다.

 

가상 메모리(Virtual memory) 개념

  • 가상 메모리논리 메모리와 물리 메모리를 분리하여, 실제 물리 메모리보다 훨씬 큰 메모리 공간을 제공하는 방식이다.
  • 개발자는 물리 메모리 크기를 신경 쓰지 않고 프로그램을 작성할 수 있다.

물리적 메모리보다 큰 가상 메모리를 보여주는 다이어그램

 

가상 주소 공간(virtual address space)

  • 프로세스가 메모리에 저장되는 방식에 대한 논리적(또는 가상) 보기를 의미
  • 가상 주소 공간은 연속적으로 보이지만, 실제 물리 메모리에서는 불연속적인 페이지 프레임으로 저장된다.
  • 스택은 아래 방향으로, 힙은 위 방향으로 성장하며, 이들 사이의 빈 공간(홀)은 동적 할당 및 공유 라이브러리 로딩 등에 활용될 수 있다.

 

메모리 내 프로세스의 가상 주소 공간

 


10.2 요구 페이징 (Demand Paging)

10.2.1 기본 개념

 

  • 요구 페이징필요한 페이지만 메모리에 로드하는 방식으로, 실행 중 참조된 페이지만 로딩하므로 메모리를 효율적으로 사용할 수 있다.
  • 실행 중 참조되지 않은 페이지는 보조 저장장치(HDD, NVM 등)에 남아 있으며, 접근 시 메모리로 가져온다.

 

일부 페이지가 메인 메모리에 없는 경우 페이지 테이블

 

요구 페이징의 작동 방식

  1. 페이지 접근 확인: 페이지 테이블에서 해당 페이지가 유효한지(valid) 확인한다.
  2. 페이지 폴트(Page Fault) 발생:
    • 페이지가 유효하지 않다면, 운영체제(OS)가 트랩을 처리하여 해당 페이지를 메모리에 로드한다.
    • 페이지 폴트 처리 과정
      페이지 폴트 처리 단계
      1. 내부 테이블 확인
      2. 유효성 검사 및 프로세스 처리
        • 잘못된 접근(Invalid Reference): 프로세스를 강제 종료(Terminate)
        • 유효한 접근(Valid Reference): 아직 메모리에 로드되지 않은 페이지이므로, 해당 페이지를 메모리에 가져옴 (Page-in)
      3. 빈 프레임 할당
      4. 보조 저장장치에서 페이지 읽기 (Disk I/O 수행)
      5. 페이지 테이블 및 내부 테이블 수정
        • 페이지가 메모리에 로드되었음을 페이지 테이블과 내부 테이블에 반영
        • 페이지 테이블의 해당 페이지를 "유효(valid)" 상태로 변경
      6. 중단된 명령어 재시작
  3. 순수 요구 페이징(Pure Demand Paging)
    • 프로세스를 실행할 때 처음에는 메모리에 아무 페이지도 로드하지 않음
    • 첫 번째 명령어를 실행하려 하면 해당 페이지가 메모리에 없으므로 페이지 폴트(Page Fault) 발생
    • 필요한 페이지가 하나씩 메모리에 로드되면서 프로그램이 실행됨
    • 결국 필요한 모든 페이지가 메모리에 로드되면 더 이상 페이지 폴트 없이 실행됨

10.4 페이지 교체(Page Replacement)

페이지 교체의 필요성

 

  • 프로세스가 실제 사용하는 페이지만 로드하면 메모리를 효율적으로 사용할 수 있음
  • 하지만 예기치 않은 메모리 부족 문제 발생 가능
  • 스와핑 대신 페이지 교체 알고리즘을 사용하여 문제 해결
  • 효율적인 페이지 교체 기법이 운영체제 성능을 결정하는 중요한 요소

페이지 교체의 필요성

 

10.4.1 Basic Page Replacement

페이지 교체의 개념

  • 운영체제에서 프로세스가 필요한 페이지가 메모리에 없는 경우(페이지 폴트 발생), 해당 페이지를 보조 저장장치에서 메모리로 불러와야 함
  • 메모리에 빈 프레임이 없다면, 기존에 사용 중인 프레임을 해제하고 새 페이지를 로드하는 과정을 페이지 교체(Page Replacement)라고 함

 

페이지 교체 과정

페이지 교체

  1. 보조 저장장치(디스크)에서 필요한 페이지의 위치를 찾음
  2. 메모리에서 빈 프레임을 찾음
    • 빈 프레임이 있다면 그대로 사용
    • 빈 프레임이 없다면, 페이지 교체 알고리즘을 사용하여 대체할 페이지(희생 페이지)를 선택
    • 선택된 페이지가 수정된 상태라면, 해당 내용을 보조 저장장치에 저장
  3. 새로운 페이지를 메모리에 로드하고, 페이지 테이블을 업데이트
  4. 페이지 폴트가 발생했던 위치에서 프로세스를 재개

수정 비트(Modify Bit, Dirty Bit) 활용

  • 수정 비트(Dirty Bit): 페이지가 메모리에 로드된 이후 수정되었는지 여부를 표시하는 비트
  • 수정된 페이지 → 페이지 교체 시 반드시 보조 저장장치에 저장해야 함
  • 수정되지 않은 페이지 → 단순히 메모리에서 제거하면 되므로 I/O 비용을 절반으로 줄일 수 있음

페이지 교체의 중요성

  • 가상 메모리 시스템에서 필수적인 기능으로, 논리 메모리와 물리 메모리를 완전히 분리할 수 있음
  • 메모리 크기에 구애받지 않고 더 큰 프로세스를 실행할 수 있도록 함
  • 효율적인 페이지 교체 알고리즘이 시스템 성능에 큰 영향을 미침

10.4.2 FIFO 페이지 교체 (FIFO Page Replacement)

  • 가장 단순한 페이지 교체 알고리즘
  • 가장 먼저 메모리에 들어온 페이지를 가장 먼저 내보냄
  • 구현 방법:
    • 각 페이지가 메모리에 들어온 시간을 기록하거나 큐(Queue) 를 사용
    • 새로운 페이지가 들어오면 큐의 맨 앞(오래된 페이지) 제거 → 맨 뒤에 새 페이지 추가

FIFO Page Replacement 알고리즘

  • 문제점:
    • 최근에 자주 사용되는 페이지도 무조건 교체될 수 있음 → 페이지 폴트 증가
    • 벨라디의 역설(Belady’s Anomaly) 발생 가능
      • 메모리 프레임 수를 늘려도 페이지 폴트 수가 증가하는 현상

10.4.3 최적 페이지 교체 (Optimal Page Replacement)

  • 가장 오랫동안 사용되지 않을 페이지를 교체하는 방식
  • 이론적으로 가장 낮은 페이지 폴트율을 보장
  • 구현 방법:
    • 앞으로 올 페이지 참조 패턴을 미리 알고 있어야 함
    • 가장 오랫동안 사용되지 않을 페이지를 선택하여 교체

Optimal Page Replacement 알고리즘

  • 문제점:
    • 실제 구현이 불가능 (미래의 페이지 참조 순서를 알 수 없음)
    • 연구 및 비교 분석을 위한 기준점으로 사용됨

10.4.4 LRU 페이지 교체 (LRU Page Replacement)

  • 가장 오랫동안 사용되지 않은 페이지를 교체하는 방식
  • 과거 데이터를 기반으로 미래를 예측 → OPT 알고리즘을 현실적으로 근사
  • 구현 방법:
    1. 카운터 방식
      • 모든 페이지에 마지막 사용 시간(time-stamp) 을 저장
      • 페이지를 교체할 때 가장 오래 전에 사용된 페이지를 제거
      • 문제점: 매번 시간 값을 업데이트하고 정렬해야 하므로 오버헤드 큼
        LRU Page Replacement 알고리즘
    2. 스택 방식
      • 페이지 번호를 스택(연결 리스트)로 관리
      • 새로운 페이지가 참조될 때 스택의 맨 위로 이동
      • 가장 오랫동안 사용되지 않은 페이지는 항상 스택의 맨 아래에 위치
      • 문제점: 스택 조작을 위한 추가적인 하드웨어가 필요

스택을 사용한 LRU Page Replacement 알고리즘

 


10.5 페이지 할당 (Allocation of Frames)

10.5.1 최소 프레임 수

  • 모든 프로세스에 최소한의 프레임을 할당해야 함.
  • 너무 적은 프레임을 할당하면 페이지 폴트가 증가하여 성능이 저하됨.
  • 특정 명령어 실행을 위해 필요한 최소 프레임 수는 컴퓨터 아키텍처에 따라 결정됨.
  • 예: 간접 주소 참조를 허용하는 경우 최소 3개 이상의 프레임이 필요함.

10.5.2 할당 알고리즘

  • 균등 할당(Equal Allocation): 모든 프로세스에 동일한 수의 프레임을 배분.
    • 예: 93개의 프레임을 5개의 프로세스에 배분하면 각 프로세스는 18개를 받음.
  • 비례 할당(Proportional Allocation): 프로세스 크기에 따라 프레임을 배분.
    • 예: 10KB 프로세스와 127KB 프로세스가 있는 경우 62개 프레임을 4:57로 나눔.
  • 우선순위 기반 할당: 프로세스 크기뿐만 아니라 우선순위를 고려하여 프레임을 배분.
    • 높은 우선순위의 프로세스가 더 많은 프레임을 받을 수 있음.

10.5.3 전역 vs 지역 할당

  • 전역 할당(Global Replacement)
    • 모든 프로세스가 시스템 전체에서 프레임을 교체할 수 있음.
    • 한 프로세스가 다른 프로세스의 프레임을 가져갈 수 있음.
    • 시스템 처리량이 증가하지만 개별 프로세스 성능이 예측 불가능해짐.
  • 지역 할당(Local Replacement)
    • 프로세스가 자신에게 할당된 프레임 내에서만 페이지 교체 가능.
    • 개별 프로세스의 성능은 안정적이지만, 전체 시스템 효율성은 떨어질 수 있음.

전역 페이지 교체 전략

  • 특정 임계값 이하로 여유 프레임이 줄어들면 커널이 페이지 교체를 시작.
  • 프레임이 최대 임계값에 도달하면 페이지 회수가 중지됨.
  • 리퍼(Reaper) 루틴이 페이지 교체를 수행하며, 보통 LRU(Least Recently Used) 방식 사용.
  • 여유 메모리가 부족하면 더욱 적극적으로 페이지 회수를 수행할 수도 있음.
  • 극단적인 경우, OOM(Out-Of-Memory) 킬러가 실행되어 메모리를 많이 사용하는 프로세스를 종료함.

10.5.4 비균일 메모리 접근(NUMA, Non-Uniform Memory Access)

  • NUMA 시스템에서는 메모리 접근 시간이 동일하지 않다고 가정
  • NUMA 시스템에서는 여러 개의 CPU가 각자의 로컬 메모리(Local Memory) 를 가지며, CPU는 자신의 로컬 메모리에 더 빠르게 접근할 수 있음.
  • 다른 CPU의 로컬 메모리에 접근할 경우 지연(latency)이 증가하여 성능이 저하됨.
  • 하지만 NUMA 시스템은 더 많은 CPU를 수용할 수 있어, 병렬 처리와 시스템 처리량을 증가 시킬 수 있음.

NUMA 멀티프로세싱 구조

 


10.6 스래싱(Thrashing)

스래싱(Thrashing)프로세스가 실행보다 페이지 교체(Page Faulting)에 더 많은 시간을 소비하는 현상을 의미함.
이로 인해 성능이 심각하게 저하되며, 시스템이 거의 멈추는 상태가 됨.


10.6.1 스래싱의 원인 (Cause of Thrashing)

기본 개념

  • 프로세스가 실행을 위해 필요한 최소한의 프레임(Frame, 페이지 저장 공간)을 확보하지 못할 경우 발생.
  • 페이지 부재(Page Fault) 발생 → 페이지 교체가 필요 → 현재 사용 중인 페이지를 교체 → 교체된 페이지가 다시 필요해 반복적인 페이지 폴트 발생.
  • 프로세스가 페이지를 계속 교체하느라 실행을 제대로 하지 못하는 상황이 됨.

스래싱

 

스래싱 발생 과정

  1. 운영체제는 CPU 사용률을 모니터링하고, 사용률이 낮으면 다중 프로그래밍 정도(실행 프로세스 수)를 증가시킴.
  2. 새로운 프로세스가 실행되면서 더 많은 프레임이 필요하게 됨.
  3. 전역 페이지 교체(Global Page Replacement)가 적용되면, 운영체제가 특정 프로세스가 아닌 전체 프로세스에서 무작위로 페이지를 교체함.
  4. 한 프로세스가 더 많은 프레임을 차지하면, 다른 프로세스들이 부족한 프레임을 가지게 되어 추가적인 페이지 부재가 발생함.
  5. 결과적으로, 모든 프로세스가 서로 프레임을 빼앗으며 페이지 교체를 반복하는 스래싱 현상 발생.

 

스래싱 발생 시 결과

  • 프로세스가 페이지 교체에만 집중 → CPU 사용률 급감.
  • 운영체제가 이를 해결하려고 더 많은 프로세스를 실행 → 문제 악화.
  • 시스템 전체의 처리량(Throughput) 급락.
  • 메모리 접근 시간 증가 → 전체 성능 저하.

 

스래싱을 줄이는 방법

  1. 로컬 교체(Local Replacement) 또는 우선순위 교체(Priority Replacement) 사용
    • 특정 프로세스가 자신에게 할당된 프레임 내에서만 페이지를 교체하도록 제한.
  2. 프로세스에 충분한 프레임 할당
    • 프로세스가 정상적으로 실행되려면 현재 실행 중인 코드와 데이터를 저장할 충분한 프레임 필요.
    • 프레임 수가 부족하면 스래싱 발생 가능성 높아짐.
  3. 지역성(Locality) 개념 활용
    • 프로세스는 특정 시간 동안 특정한 페이지 집합(지역성, Locality)을 집중적으로 사용.
    • 지역성이 유지되는 동안 필요한 페이지를 미리 로드하면 페이지 폴트를 줄일 수 있음.
      • 지역성(Locality) 개념과 스래싱 방지
        • 프로세스는 실행 중에 지역성을 변경하면서 새로운 페이지 집합을 사용.
        • 운영체제가 현재 지역성을 유지할 수 있는 충분한 프레임을 할당하면 스래싱 방지 가능.
        • 반대로, 현재 지역성 크기보다 적은 프레임을 할당하면 스래싱 발생.

메모리 참조 패턴의 지역성

 

위 그림에서 '시간 a'의 지역성은 페이지 집합 {18, 19, 20, 21, 22, 23, 24, 29, 30, 33} 이다. '시간 b'의 지역성은 페이지 집합 {18, 19, 20, 24, 25, 26, 27, 28, 29, 31, 32, 33} 으로 변경


10.6.2 작업-집합 모델 (Working-Set Model)

변화량만큼 페이지 참조를 관찰하여 그 안에 들어있는 서로 다른 페이지들의 집합을 작업 집합(working set)이라 한다.

작업-집합 모델


10.6.3 페이지 폴트 빈도(Page-Fault Frequency)

페이지 폴트 빈도

  • 스래싱은 높은 페이지 폴트 비율을 동반하므로, 페이지 폴트 비율의 상한선과 하한선을 두어 조절함
  • 상한선 및 하한선 설정: 실제 페이지 부재율이 상한선을 초과하면 해당 프로세스에 프레임을 추가로 할당하고, 반대로 하한선 아래로 떨어지면 프레임을 회수한다.
  • 프로세스 스와핑: 만약 페이지 부재율이 증가하고 더 이상 사용 가능한 프레임이 없다면, 일부 프로세스를 백업 저장소로 스와핑하여 프레임을 해방시킨다. 이렇게 해방된 프레임은 높은 페이지 부재율을 보이는 다른 프로세스에 재분배.

10.7 메모리 압축(Memory Compression)

  • 메모리 압축은 페이징(Paging)의 대안으로, 프레임을 압축하여 메모리에 저장하는 방식.
  • 장점: 메모리 사용량을 줄이면서도 성능 저하를 최소화할 수 있음.

 

메모리 압축의 원리

  • 운영체제는 일정 기준 이하로 사용 가능한 프레임 수가 줄어들면 페이지 교체를 수행.
  • 기존 방식(페이징): 프레임을 스왑 공간으로 이동 → 이후 다시 로드할 때 페이지 폴트(Page Fault) 발생.
  • 메모리 압축 방식:
    1. 여러 개의 프레임을 하나의 프레임에 압축하여 저장.
    2. 압축된 프레임은 ‘압축 프레임 리스트(Compressed Frame List)’에 저장.
    3. 필요할 경우 압축 해제하여 원래 프레임을 복원(페이지 폴트 발생 시).

 

예시> 압축전

압축 전 상황

  • 사용 가능한 free-frame 리스트에 여유 공간이 6개 있음.
  • 프레임 15, 3, 35, 26이 페이지 교체 대상으로 선택됨.
  • 기존 방식이라면 이 프레임들이 스왑 공간으로 이동.

압축후

압축 후 상황

 

  • 프레임 15, 3, 35를 하나의 프레임(프레임 7)에 압축 저장.
  • 이제 15, 3, 35는 free-frame 리스트에서 제거되고, 대신 프레임 7이 압축 프레임 리스트에 추가됨.
  • 필요하면 압축 해제 후 다시 메모리에 복구.

10.8 커널 메모리 할당 (Allocating Kernel Memory)

  • 운영체제에서 커널(Kernel)은 자체적인 메모리 할당 방식이 필요함.
  • 이유:
    1. 커널은 다양한 크기의 데이터 구조를 요청 → 조각화(Fragmentation) 방지 필요
    2. 물리 메모리에 직접 접근하는 특정 하드웨어 장치는 연속된(Contiguous) 메모리를 요구

이를 해결하기 위한 두 가지 커널 메모리 할당 전략

  1. 버디 시스템(Buddy System)
  2. 슬랩 할당(Slab Allocation)

10.8.1 버디 시스템 (Buddy System)

 

  • 연속된(Contiguous) 페이지 단위의 메모리를 고정 크기로 분할하여 할당하는 방식.
  • 2의 거듭제곱 단위(4KB, 8KB, 16KB...)로 메모리를 분할하여 관리.
  • 요청된 크기보다 큰 가장 작은 2의 거듭제곱 크기 메모리를 할당.
    • 예: 11KB 요청 → 16KB 할당
    • 예: 21KB 요청 → 32KB 할당

버디 시스템

버디 시스템 할당 예시

  1. 초기 메모리 크기: 256KB
  2. 21KB 요청 발생 → 32KB 할당 필요
  3. 256KB를 두 개의 128KB로 분할 → 128KB를 다시 64KB로 분할
  4. 64KB를 다시 32KB로 분할 → 32KB 중 21KB를 사용 (나머지는 내부 단편화)
  5. 할당된 32KB는 버디(짝) 시스템(CL, CR) 중 CL에 배정됨

10.8.2 슬랩 할당 (Slab Allocation)

 

  • 슬랩(Slab): 하나 이상의 연속된(Contiguous) 페이지로 구성된 메모리 블록
  • 캐시(Cache): 특정 커널 데이터 구조를 저장하는 공간
  • 객체(Object): 특정 커널 데이터 구조의 인스턴스

슬랩 할당의 메모리 상태

  1. Full (모든 객체 사용 중)
  2. Empty (모든 객체 사용 가능)
  3. Partial (일부 사용 중, 일부 사용 가능)

슬랩 할당

 

슬랩 할당 예시

  • 리눅스에서 프로세스 디스크립터(Process Descriptor) 할당 시
    • struct task_struct 데이터 구조 사용 (약 1.7KB 필요)
    • 슬랩 할당자는 이미 존재하는 객체 중 사용되지 않은 것을 할당
    • 새로운 객체가 필요하면 슬랩을 확장하여 추가 할당