Krafton Jungle/2. Keywords

[WEEK13] VM 관련 키워드 정리

munsik22 2025. 6. 10. 10:41

Virtual Memory (가상 메모리)

개요

가상 메모리는 물리 메모리의 추상화된 버전이다. 즉, 프로세스가 실제 물리 주소를 직접 다루지 않고 가상의 주소 공간Virtual Address Space을 통해 메모리에 접근하는 구조이다. 이 방식은 각 프로세스가 자신만의 독립된 주소 공간을 가지는 것처럼 보이게 하며, 메모리 보호 및 효율적인 자원 활용을 가능하게 한다.

목적

  • 메모리 보호 (Isolation): 서로 다른 프로세스의 메모리 공간이 완전히 분리된다.
  • 효율적인 메모리 사용 (Demand Paging): 실제로 사용되는 페이지만 물리 메모리에 올려서 메모리 낭비를 줄인다.
  • 스와핑 및 오버커밋 (Swapping & Overcommit): 디스크 공간을 이용해 물리 메모리보다 더 큰 주소 공간을 제공할 수 있다.

주소 변환

  • 프로세스가 CPU에 가상 주소Virtual Address를 제공하면, 이는 MMUMemory Management Unit에 의해 물리 주소Physical Address로 변환된다.
  • 이 변환 과정의 핵심이 바로 페이지 테이블Page Table이며, 빠른 변환을 위해 TLB를 사용한다.

Page Table (페이지 테이블)

정의

페이지 테이블은 가상 주소를 물리 주소로 매핑하는 데이터 구조이다. 각 가상 페이지 번호에 대응하는 물리 프레임 번호가 저장되어 있다.

동작 원리

가상 주소는 보통 다음과 같이 나뉜다:

가상 주소 = [페이지 번호(Page Number)] + [페이지 오프셋(Page Offset)]
  • 예시:
    • 페이지 크기: 4KB (2¹²)
    • 32-bit 주소 공간: 2³² = 4GB
    • 총 페이지 수: 2²⁰
  • 이 경우 가상 주소의 상위 20비트는 페이지 번호, 하위 12비트는 오프셋이 된다.
  • CPU가 가상 주소를 요청하면:
    1. 페이지 번호를 추출
    2. 페이지 테이블에서 해당 페이지 번호에 대응되는 프레임 번호를 검색
    3. 해당 프레임의 시작 주소 + 오프셋 = 최종 물리 주소

종류

  • 단일 레벨 페이지 테이블: 가장 단순한 형태이지만 메모리 낭비가 심하다.
  • 다단계 페이지 테이블: 페이지 테이블 자체도 계층화해서, 필요할 때만 하위 테이블을 생성한다.
  • 인버티드 페이지 테이블: 페이지 테이블을 물리 메모리 기준으로 구성하여 메모리 공간 절약 가능.

페이지 테이블 엔트리 (Page Table Entry, PTE)

하나의 페이지 테이블 항목은 다음과 같은 정보를 가진다:

  • 프레임 번호 (Frame Number)
  • 유효 비트 (Valid/Present Bit)
  • 접근 권한 비트 (Read/Write/Execute)
  • 수정 비트 (Dirty Bit)
  • 참조 비트 (Accessed Bit)

TLB (Translation Lookaside Buffer)

정의

TLB는 페이지 테이블의 캐시이다. 자주 참조되는 페이지 번호와 물리 프레임의 매핑을 빠르게 찾아내기 위해 사용된다.

목적

  • 페이지 테이블 접근은 메모리를 두 번 읽는 과정이므로 느리다.
  • 이를 보완하기 위해 MMU 내부에 작고 빠른 하드웨어 캐시인 TLB를 두고, 최근 변환 정보를 저장한다.
  • TLB는 L1 캐시와 유사한 역할을 한다.

동작

  1. CPU가 가상 주소를 사용하면, MMU는 먼저 TLB를 조회한다.
  2. TLB에 해당 페이지 번호가 존재(TLB hit)하면 → 바로 물리 주소를 얻는다.
  3. 없다면(TLB miss) → 페이지 테이블을 조회해 매핑을 찾고, 그 결과를 TLB에 저장한다.

TLB 관리

  • TLB Miss 핸들링: OS 또는 하드웨어가 페이지 테이블을 참조해 TLB를 갱신한다.
  • Context Switch 시 TLB 초기화 또는 컨텍스트 태그 사용: 다른 프로세스의 주소 공간을 오염시키지 않기 위해.

TLB 항목 구성

  • 가상 페이지 번호
  • 물리 프레임 번호
  • 접근 권한 정보
  • 유효 비트 및 태그

TLB 크기와 속도

  • 보통 16~512개 엔트리로 구성
  • 매우 빠르지만, 용량이 작기 때문에 캐시 정책(LRU, FIFO 등)이 중요

Page Fault (페이지 폴트)

페이지 폴트는 CPU가 어떤 가상 주소에 접근하려고 했을 때, 해당 주소에 대응되는 물리 프레임이 현재 메모리에 존재하지 않는 경우에 발생하는 예외 상황이다. 이 상황은 반드시 오류를 뜻하는 것이 아니라, 오히려 가상 메모리의 핵심 기능을 가능하게 하는 메커니즘이다.

페이지 폴트 발생 조건

가상 주소에 접근 시 다음 중 하나라도 해당되면 페이지 폴트가 발생한다.

  1. 해당 페이지가 아직 물리 메모리에 로드되지 않은 경우 (lazy loading, demand paging)
  2. 접근 권한이 없는 페이지에 접근한 경우 (예: 읽기 전용 페이지에 쓰기 시도)
  3. 페이지가 스왑 아웃되어 디스크에만 존재하는 경우

처리 과정

페이지 폴트가 발생하면 운영체제는 다음과 같은 순서로 이를 처리한다.

  1. 커널은 페이지 폴트 예외를 감지하고, faulting address를 확인한다.
  2. 이 주소가 유효한지 확인한다: 해당 프로세스의 주소 공간 내에 존재하는가?
  3. 유효하다면, 해당 주소에 대응되는 페이지를 디스크에서 로드하거나 스택을 확장한다.
  4. 페이지가 들어갈 물리 메모리 프레임을 확보한다: 필요 시 기존 페이지를 교체
  5. 페이지 테이블을 갱신하고, TLB를 갱신한다.
  6. 폴트가 발생한 명령어를 재시도한다.

잘못된 접근일 경우

주소가 유효하지 않거나, 접근 권한이 없는 경우에는 페이지 폴트는 recoverable하지 않으며, 일반적으로 segmentation fault 등의 오류로 프로세스가 종료된다.


Lazy Loading (지연 로딩)

레이지 로딩은 프로그램 실행 시 모든 페이지를 한 번에 메모리에 올리는 것이 아니라, 실제로 필요한 시점에만 로드하는 전략이다. 이는 물리 메모리를 절약하고 프로그램 실행 속도를 높이기 위한 대표적인 최적화 기법이다.

배경

  • 전통적인 방식은 프로그램 전체를 메모리에 올린다 (eager loading)
  • 그러나 실제로 모든 코드나 데이터가 한 번에 사용되지는 않는다
  • 예: 어떤 함수는 실행되지 않을 수도 있다

동작 방식

  1. 초기 실행 시 실행 파일의 세그먼트는 메모리에 로드하지 않고, 페이지 테이블에 "아직 로드되지 않음" 표시만 남긴다.
  2. CPU가 해당 주소에 접근하면 페이지 폴트가 발생한다.
  3. 운영체제는 그 시점에 디스크에서 해당 데이터(또는 코드)를 읽어와 메모리에 올린다.
  4. 이후 접근 시에는 정상적으로 물리 메모리에 존재하게 된다.

구현 포인트

  • supplemental page table과 같은 구조체를 통해 어떤 페이지가 어떻게 로드되어야 하는지 메타 정보를 저장한다.
  • 초기에는 present 비트를 0으로 설정하여 TLB나 MMU가 페이지 폴트를 발생시키게 유도한다.
  • 실제 디스크에서의 로드는 I/O 연산을 포함하므로 느리지만, 한번 로딩된 페이지는 다시 디스크에서 읽지 않아도 된다 (캐시됨).

Page Replacement Policy (페이지 교체 정책)

가상 메모리에서 물리 메모리는 한정되어 있으므로, 새로운 페이지를 로드해야 할 때 빈 공간이 없다면 기존에 로드된 페이지 중 일부를 제거해야 한다. 이때 어떤 페이지를 제거할지를 결정하는 알고리즘이 바로 페이지 교체 정책이다.

기본 원리

  • 교체 대상은 현재 물리 메모리에 존재하는 페이지 중에서 선택된다.
  • 가능한 한 다시 사용되지 않을 가능성이 높은 페이지를 제거하는 것이 이상적이다.

주요 정책

  • FIFO (First-In, First-Out)
    • 가장 먼저 메모리에 들어온 페이지를 가장 먼저 교체
    • 간단하지만, 실제 접근 패턴과 무관하게 작동하기 때문에 성능이 낮은 경우가 많다
  • LRU (Least Recently Used)
    • 가장 오랫동안 참조되지 않은 페이지를 교체
    • 실제로 잘 작동하는 정책이지만, 정확한 LRU 구현은 비용이 크다 (하드웨어 지원 또는 추정 기반 필요)
  • Clock (Second-Chance)
    • 원형 큐로 구현되며, 각 페이지마다 참조 비트(reference bit)를 사용
    • 참조 비트가 0인 페이지를 교체 대상으로 삼고, 1이면 비트를 0으로 만들고 패스
    • LRU의 근사치로, 실제 구현에 많이 사용된다고 한다
  • NRU (Not Recently Used)
    • 주기적으로 참조 비트와 수정 비트를 조합해 4개 클래스로 나눈 후 가장 낮은 클래스를 교체
    • 대체로 운영체제 수업에서 이론적으로 설명되며 실제 사용은 드물다

스와핑과의 관계

  • 페이지 교체 시 대상 페이지가 dirty(수정됨) 상태라면 디스크에 다시 저장해야 하므로 오버헤드가 크다
  • 수정되지 않은 페이지는 단순히 제거하면 되고, 필요 시 다시 읽어오면 된다

Anonymous Page (익명 페이지)

개념

익명 페이지란 특정한 파일에 연관되지 않은 메모리 페이지를 의미한다. 다시 말해, 디스크 상의 어떤 파일로부터 데이터를 로드해서 만들어진 것이 아니라, 단순히 프로그램 실행 중 동적으로 생성된 메모리 공간이다.

예시

  • 프로그램에서 malloc(), new, brk() 또는 sbrk()를 통해 동적 메모리를 요청했을 때
  • 사용자 스택, 힙 영역
  • mmap을 사용할 때 MAP_ANONYMOUS 플래그가 지정된 경우

특징

  • 파일과 연계되어 있지 않기 때문에, 해당 페이지를 재구성하려면 스왑 디스크에 저장해놔야 한다.
  • 초기에는 전부 제로 페이지로 할당되거나, lazy allocation으로 지연 생성될 수 있다.
  • 접근 시 페이지 폴트가 발생하고, 그때 물리 페이지가 할당된다.

관리

  • 보통 운영체제는 이러한 페이지를 swap 영역에 저장하며, 필요에 따라 다시 메모리에 로드한다.
  • 익명 페이지는 swap-in, swap-out 대상이 된다.

Swap Disk (스왑 디스크)

개념

스왑 디스크는 물리 메모리가 부족할 때, 임시로 페이지 데이터를 저장하는 공간이다. 보통 하드디스크 또는 SSD의 일부 파티션 또는 파일을 스왑 영역으로 지정한다.

목적

  • 물리 메모리 한계를 넘는 가상 주소 공간을 제공하기 위해
  • 오랫동안 사용되지 않은 페이지를 메모리에서 제거하고, 디스크에 저장함으로써 새로운 페이지를 위한 공간 확보

동작 방식

  1. 페이지 폴트나 메모리 부족이 발생
  2. 교체 대상 페이지가 선택됨
  3. 해당 페이지가 스왑 디스크에 저장됨
  4. 페이지 테이블의 해당 엔트리에 "디스크에 존재" 표시 (present bit = 0, swapped = 1)
  5. 새로운 페이지가 들어올 공간 확보됨

성능 상의 이슈

  • 스왑은 메모리보다 수천 배 느린 I/O 연산이다
  • 스왑 인/아웃이 자주 발생하면 전체 시스템이 느려지는 thrashing 현상이 발생할 수 있다

File-backed Page (파일 기반 페이지)

개념

파일 기반 페이지는 디스크 상의 특정 파일 내용과 직접 연결되어 있는 페이지이다. 예를 들어 실행 파일의 코드 섹션, 읽기 전용 데이터, mmap으로 매핑된 파일의 일부 등이 이에 해당한다.

예시

  • 실행 파일의 .text, .rodata 세그먼트
  • mmap("/tmp/data.txt")로 특정 파일을 메모리에 매핑한 경우
  • 공유 라이브러리(.so)의 매핑

특징

  • 페이지에 저장된 데이터는 디스크의 파일과 일치한다
  • 파일에서 직접 페이지 내용을 읽어오며, 수정되지 않았다면 메모리에서 제거해도 디스크에서 복구 가능
  • 일부 페이지는 수정될 수 있으며, 이 경우 dirty 상태로 관리된다

Lazy loading과의 연계

  • 초기에는 파일만 매핑하고, 실제 페이지는 로드하지 않음
  • 접근 시 페이지 폴트를 통해 파일에서 해당 부분을 읽어와 메모리에 로드한다

swap과의 차이점

  • Anon page는 스왑 디스크에만 저장 가능
  • File page는 원본 파일이 디스크에 존재하므로, 수정되지 않았다면 스왑 저장이 필요 없다

Direct Memory Access (DMA)

DMA는 CPU의 개입 없이 장치가 메인 메모리와 직접 데이터를 주고받을 수 있게 해주는 기능이다. 이를 통해 I/O 작업에서의 CPU 오버헤드를 줄이고 성능을 개선할 수 있다.

배경

  • 전통적인 I/O: CPU가 장치에서 데이터를 하나하나 읽어와 메모리에 저장 (비효율적)
  • DMA: 장치가 메모리 주소를 직접 지정하고, 데이터를 전송

구성 요소

  • DMA Controller (DMA 컨트롤러): 장치와 메모리 간 전송을 중재
  • 버스 접근 권한: 장치가 직접 메모리 버스를 사용할 수 있도록 지원
  • 전송 완료 시 인터럽트 발생

동작 흐름

  1. CPU가 DMA 설정 (버퍼 주소, 크기 등)
  2. DMA 컨트롤러가 데이터를 장치 ↔ 메모리 간 전송
  3. 전송이 완료되면 DMA가 CPU에 인터럽트를 발생시켜 완료를 알림
  4. CPU는 이 시점에 처리 결과만 확인하면 됨

응용 예시

  • 디스크 I/O (파일 읽기, 쓰기)
  • 네트워크 카드에서 데이터 수신 시
  • 그래픽 카드의 프레임 버퍼 전송

장점

  • CPU의 부하 감소
  • 데이터 전송 속도 증가
  • CPU는 다른 작업을 수행하면서도 I/O 동작을 병행할 수 있음

Paging (페이징)

페이징은 가상 메모리 공간을 고정된 크기의 블록(= 페이지, page)로 나누고, 물리 메모리도 동일한 크기의 블록(= 프레임, frame)으로 나누어, 페이지 단위로 주소를 매핑하는 방식이다. 이 방식을 통해 프로세스는 연속적인 가상 주소 공간을 사용하는 것처럼 보이지만, 실제로는 불연속적인 물리 주소 공간에 저장될 수 있다.

주소 변환 (Address Translation)

  • 가상 주소는 보통 다음 두 부분으로 구성된다:
    • 상위 비트: 페이지 번호 (Page Number)
    • 하위 비트: 페이지 오프셋 (Page Offset)
  • 예를 들어,
    • 페이지 크기가 4KB라면 오프셋은 12비트,
    • 나머지 비트는 페이지 번호가 된다.
  • 변환 과정은 다음과 같다:
    1. CPU는 가상 주소를 생성
    2. MMU는 상위 비트(페이지 번호)를 페이지 테이블에서 찾음
    3. 페이지 테이블이 해당 페이지가 매핑된 프레임 번호를 반환
    4. 프레임 번호에 오프셋을 더해서 실제 물리 주소 계산

페이징 구조 예시

  • 가상 주소: 0xABCDEF
    • 페이지 크기: 4KB → 12비트 오프셋
    • 페이지 번호: 0xABCDE
    • 오프셋: 0xF
  • 페이지 테이블에서 페이지 번호 0xABCDE가 매핑된 프레임 번호 0x321을 반환했다면,
    실제 물리 주소는 0x321000 + 0xF = 0x32100F가 된다.

왜 페이징이 필요한가?

  • 외부 단편화External Fragmentation 해결: 연속된 물리 메모리 공간을 요구하지 않기 때문에, 다양한 프로세스의 메모리를 효율적으로 배치할 수 있다.
  • 메모리 보호: 각 프로세스마다 독립적인 페이지 테이블을 유지하여, 서로의 메모리에 접근하지 못하게 한다.
  • 스왑 및 지연 로딩에 적합: 페이지 단위로 메모리를 관리하므로, 일부 페이지만 디스크에서 로드하거나, 스왑 디스크로 이동시키는 것이 가능하다.

페이지 테이블 (Page Table)

  • 각 프로세스는 자신의 페이지 테이블을 가지고 있으며, 여기서 페이지 번호를 물리 프레임 번호로 매핑한다.
  • 각 항목(PTE, Page Table Entry)은 다음과 같은 정보를 포함한다:
    • 프레임 번호
    • 존재 여부 (present bit)
    • 읽기/쓰기 권한
    • dirty bit (수정 여부)
    • accessed bit (최근 사용 여부)

다단계 페이징 (Multilevel Paging)

  • 전체 가상 주소 공간을 커버하려면 거대한 페이지 테이블이 필요하다.
  • 이를 해결하기 위해 페이지 테이블 자체도 페이징하는 방식을 사용한다.
  • 예: 32비트 주소 공간에서 2단계 페이징을 적용
    • 상위 10비트: 디렉토리 인덱스
    • 중간 10비트: 테이블 인덱스
    • 하위 12비트: 오프셋

TLB와의 연계

  • 페이지 테이블은 메모리에 저장되므로 접근 속도가 느리다.
  • 이를 해결하기 위해 TLB 캐시를 사용
  • 최근에 접근한 페이지 번호 → 프레임 번호 매핑을 빠르게 조회

장점

  • 외부 단편화 제거
  • 효율적인 메모리 보호
  • 지연 로딩 및 스왑 용이
  • 프로세스 간 주소 공간 격리

단점

  • 페이지 테이블 오버헤드: 테이블 자체가 커지며 메모리 차지
  • 주소 변환 속도 저하: TLB 미스 시 페이지 테이블을 따라가야 해서 느려짐
  • 내부 단편화 가능성: 페이지 크기가 클수록 마지막 페이지는 남는 공간이 생긴다

다음 글도 참고해 보자.

 

[WEEK07] 가상 메모리와 페이징

가상메모리(VM)Physical AddressingVirtual Addressing메모리 주소는 메모리의 정확한 장소를 참조한다.(단순한 시스템에서만 사용됨)메모리 주소는 HW의 MMU를 통해 물리적 메모리에 매핑된 process-specific addr

munsik22.tistory.com


Copy-on-Write

Copy-on-Write는 말 그대로 쓰기 시점에 복사하는 방식이다. 처음에는 여러 개의 객체 또는 프로세스가 하나의 메모리 블록을 공유하지만, 실제로 데이터를 수정하려고 할 때에만 복사가 일어난다. 일반적인 복사와는 달리, 읽기만 하는 동안은 복사가 일어나지 않기 때문에 매우 효율적이다.

동작 원리

  1. 프로세스 A가 메모리 블록 X를 가지고 있다.
  2. 프로세스 B가 fork를 통해 생성되면, A와 B는 X를 공유하게 된다. (복사 없이 공유)
  3. A 또는 B 중 하나가 X를 수정하려 하면, 운영체제가 해당 페이지에 대한 페이지 폴트를 발생시킨다.
  4. 페이지 폴트 핸들러는 해당 페이지를 실제로 복사하고, 새로운 프레임에 매핑한다.
  5. 수정은 복사된 페이지에서 이루어진다.
[초기 상태: 공유]
   A → [Page X] ← B

[쓰기 시도: B가 Page X를 수정]
   A → [Page X]
   B → [Page X']   (복사본 생성 후 쓰기)

주요 적용 사례

  • fork() 시스템 콜
    • 유닉스 계열 운영체제에서 부모 프로세스와 자식 프로세스를 복제할 때 사용
    • COW를 사용하지 않으면 수 MB ~ 수 GB의 메모리를 복사하는 오버헤드 발생
    • COW를 사용하면 읽기 시에는 메모리를 공유하고, 쓰기 시에만 복사
  • mmap()과 MAP_PRIVATE
    • 파일을 메모리에 매핑할 때, 변경 사항이 실제 파일에 반영되지 않도록 하려면 복사 필요
    • MAP_PRIVATE 플래그가 설정되면 COW 방식으로 처리됨
  • 가상 머신, 컨테이너
    • 여러 VM 또는 컨테이너가 같은 OS 이미지를 공유하되, 변경 시에만 분리된 복사본을 유지

구현 방식 (OS 내부 관점)

  1. 페이지 테이블의 해당 페이지 항목(PTE)에 읽기 전용으로 설정한다.
  2. 물리 페이지마다 참조 카운터를 유지한다 (누가 공유 중인지 추적)
  3. 쓰기가 발생하면 page fault가 발생함
  4. 커널은 참조 카운터를 확인한 후:
    • 공유 중인 페이지이면 → 새로운 물리 페이지 할당 후 복사
    • 유일한 참조라면 → 쓰기 허용만 하면 됨 (복사 불필요)
  5. PTE를 새 프레임으로 업데이트하고, 쓰기 권한도 설정

장점

  • 메모리 절약: 불필요한 복사를 피할 수 있다
  • 성능 향상: fork 후 바로 exec할 경우 복사가 아예 생략됨
  • 가상화 및 컨테이너 환경에 유리함

단점

  • 쓰기가 발생할 경우 복사 비용이 지연되어 나타나므로 예측이 어렵다
  • 페이지 단위로 복사가 일어나기 때문에 작은 변경이라도 전체 페이지 복사가 필요
  • 멀티스레드 환경에서 동기화 문제나 race condition 방지 필요