← 목록으로
컴퓨팅·임베디드
#가상메모리#요구페이징#페이지교체#LRU#워킹셋
최종 업데이트 · 2026-10-29

가상 메모리(Virtual Memory)와 페이지 교체 알고리즘

1. 개요

가. 정의

가상 메모리는 각 프로세스에게 물리 메모리 크기와 무관한 연속적이고 독립적인 주소 공간(가상 주소 공간)을 제공하고, 실행에 실제로 필요한 부분만 물리 메모리에 올려 두는 운영체제의 메모리 관리 기법이다. 그 핵심 실현 수단이 요구 페이징(demand paging)이며, 물리 메모리가 가득 찼을 때 어떤 페이지를 내보낼지 결정하는 규칙이 페이지 교체 알고리즘이다.

가상 메모리의 근본 발상은 "프로그램 전체가 동시에 메모리에 있을 필요는 없다"는 관찰에서 출발한다. 대부분의 프로그램은 특정 시점에 코드·데이터의 일부 영역만 집중적으로 참조하므로(지역성), 실행 중인 부분만 물리 메모리에 두고 나머지는 디스크(스왑 영역)에 남겨 두어도 정상 동작한다. 운영체제는 가상 주소를 물리 주소로 변환하는 MMU(Memory Management Unit)와 페이지 테이블을 통해 이 환상을 만들어 내며, 프로그래머는 물리 메모리 용량을 거의 의식하지 않고 큰 주소 공간을 다룰 수 있다.

나. 등장 배경과 필요성

초기 시스템에서는 프로그램 전체가 물리 메모리에 올라가야 실행이 가능했다. 이 제약은 두 가지 심각한 문제를 낳았다. 첫째, 물리 메모리보다 큰 프로그램은 실행 자체가 불가능했고, 개발자는 오버레이(overlay)를 손수 설계해 코드 조각을 교대로 올렸다. 둘째, 다중 프로그래밍 수준이 물리 메모리 용량에 묶여 동시에 돌릴 수 있는 프로세스 수가 제한되었다. 가상 메모리는 "실제 필요한 부분만 적재"함으로써 이 두 제약을 동시에 풀어, 물리 메모리를 초과하는 프로그램 실행과 높은 다중 프로그래밍 수준을 모두 가능하게 했다.

무엇보다 가상 메모리는 프로그래밍 모델 자체를 단순화했다. 개발자는 자신의 프로그램이 물리 메모리 어디에 적재되는지, 다른 프로그램과 어떻게 공간을 나누는지 전혀 신경 쓰지 않고 0번지부터 시작하는 깨끗하고 연속적인 주소 공간을 가정하고 코딩할 수 있다. 재배치(relocation)와 보호를 하드웨어·OS가 투명하게 처리해 주기 때문이며, 이 추상화가 없었다면 컴파일러·링커·로더의 복잡도는 지금과 비교할 수 없이 커졌을 것이다.

필요성은 오늘날 더 커졌다. 한 서버에서 수백 개의 컨테이너·프로세스가 동시에 돌고, 각 프로세스는 수 GB의 가상 주소 공간을 쓰지만 실제 상주 집합(RSS)은 그 일부에 불과하다. 가상 메모리가 없다면 이런 과잉 할당(overcommit) 기반의 밀도 높은 자원 공유는 불가능하다. 또한 가상 주소 공간의 격리는 프로세스 간 보호(한 프로세스가 다른 프로세스 메모리를 침범하지 못함)의 토대가 되며, 공유 라이브러리의 메모리 공유, mmap 기반 파일 매핑, 쓰기 시 복사(Copy-on-Write) 같은 현대 OS의 핵심 기능이 모두 가상 메모리 위에 선다.

다. 특징

가상 메모리는 몇 가지 본질적 특징을 지닌다. 첫째, 투명성으로 응용 프로그램은 자신이 요구 페이징되고 있다는 사실을 몰라도 된다. 둘째, 지역성 의존성이다. 가상 메모리의 성능은 참조의 시간적·공간적 지역성이 좋을수록 급격히 향상되며, 지역성이 무너지면 성능도 무너진다. 셋째, 디스크 I/O와의 강한 결합으로, 페이지 폴트가 발생하면 수십 마이크로초수 밀리초의 디스크 접근이 끼어들어 CPU 수천수만 사이클에 해당하는 지연이 생긴다. 바로 이 거대한 비용 격차 때문에 페이지 폴트율을 낮추는 교체 알고리즘의 품질이 시스템 성능을 좌우한다.

이러한 특징들은 가상 메모리가 메모리 계층구조(memory hierarchy)의 한 층위라는 사실에서 비롯된다. 레지스터-캐시-메인메모리-보조기억장치로 이어지는 계층에서, 가상 메모리는 "메인 메모리를 보조기억장치의 캐시처럼 쓰는" 메커니즘에 해당한다. CPU 캐시가 메인 메모리의 블록을 자동 승강시키듯 가상 메모리는 디스크의 페이지를 메모리로 승강시키며, 캐시의 지역성·교체·일관성 개념이 그대로 페이지 수준에서 재현된다. 다만 미스(폴트) 비용이 캐시 미스보다 수천 배 커서, 하드웨어가 전담하는 캐시와 달리 소프트웨어(OS)가 정교한 정책으로 개입한다는 점이 결정적 차이다.

2. 가상 메모리의 동작 구조

가상 메모리는 가상 주소를 물리 주소로 변환하는 과정과, 참조하려는 페이지가 물리 메모리에 없을 때 디스크에서 끌어오는 과정으로 나뉜다. 아래는 주소 변환과 요구 페이징의 전체 구조도다.

flowchart TD
    CPU["CPU: 가상주소 생성"] --> TLB{"TLB 조회"}
    TLB -->|"적중(hit)"| PA["물리주소 계산"]
    TLB -->|"실패(miss)"| PT["페이지 테이블 조회"]
    PT --> V{"유효비트(valid)?"}
    V -->|"1 (메모리 상주)"| PA
    V -->|"0 (디스크)"| PF["페이지 폴트 발생"]
    PF --> OS["OS 폴트 핸들러"]
    OS --> FREE{"빈 프레임 존재?"}
    FREE -->|"예"| LOAD["디스크에서 페이지 적재"]
    FREE -->|"아니오"| REPL["페이지 교체 알고리즘<br/>희생 페이지 선정"]
    REPL --> DIRTY{"수정비트(dirty)?"}
    DIRTY -->|"1"| WB["변경분 디스크 기록(write-back)"]
    DIRTY -->|"0"| LOAD
    WB --> LOAD
    LOAD --> UPD["페이지 테이블·TLB 갱신"]
    UPD --> PA
    PA --> MEM["메모리 접근 완료"]

주소 변환의 1차 관문은 TLB(Translation Lookaside Buffer)다. 최근 사용한 가상→물리 변환을 캐싱해 대부분의 접근을 수 사이클에 끝내며, TLB가 실패해야 비로소 느린 페이지 테이블 워크(계층형 테이블에서는 여러 번의 메모리 접근)가 일어난다. 페이지 테이블의 각 항목에는 프레임 번호와 함께 유효비트(메모리 상주 여부)·수정비트(dirty)·참조비트(reference)·보호비트 등이 담겨, 교체 알고리즘과 보호 메커니즘의 판단 근거가 된다.

주소 변환에는 페이지 크기라는 중요한 설계 변수가 숨어 있다. 페이지가 작으면 내부 단편화는 줄지만 페이지 테이블 항목 수와 TLB 압박이 커지고, 페이지가 크면 테이블·TLB 효율은 좋아지지만 "필요 없는 영역까지 함께 적재"되는 손실과 내부 단편화가 늘어난다. 범용 OS가 4KB를 기본값으로 오래 유지해 온 것은 이 상충의 역사적 균형점이며, 5절에서 다룰 거대 페이지는 이 기본값을 특정 워크로드에서 의도적으로 깨뜨려 TLB 효율을 극대화하는 선택이다.

가. 요구 페이징과 페이지 폴트 처리

요구 페이징은 페이지를 참조되는 순간에만 적재한다. 유효비트가 0인 페이지를 참조하면 하드웨어가 트랩을 걸어 페이지 폴트를 일으키고, OS 핸들러가 ①주소 유효성 검증 → ②빈 프레임 확보(없으면 교체) → ③디스크에서 페이지 적재 → ④페이지 테이블·TLB 갱신 → ⑤실패한 명령어 재실행의 순서로 처리한다. 이때 희생 페이지의 수정비트가 1이면 디스크에 먼저 기록(write-back)해야 하므로 두 번의 디스크 I/O가 필요하고, 0이면 기록을 생략할 수 있다 — 교체 대상 선정 시 "깨끗한 페이지"를 선호하는 이유다.

나. 가상 메모리가 떠받치는 핵심 기능 — CoW와 메모리 매핑

가상 메모리는 단순히 "메모리를 늘려 주는" 장치가 아니라, 현대 OS의 여러 핵심 기능이 올라서는 토대다. 대표가 쓰기 시 복사(Copy-on-Write)다. fork()로 자식 프로세스를 만들 때 부모의 전체 메모리를 즉시 복제하면 비용이 막대하므로, OS는 두 프로세스가 같은 물리 프레임을 읽기 전용으로 공유하게 하고 어느 한쪽이 쓰기를 시도하는 순간에만 해당 페이지를 복제한다. 이 지연 복제는 변환 계층(페이지 테이블의 보호비트)과 페이지 폴트 메커니즘이 없으면 구현할 수 없으며, fork 직후 exec하는 흔한 패턴에서 불필요한 복사를 거의 전부 제거한다.

또 하나는 메모리 매핑(mmap)이다. 파일을 가상 주소 공간에 매핑하면 read/write 시스템 호출 없이 포인터 접근만으로 파일을 다루고, 커널이 요구 페이징으로 필요한 블록만 적재하며 수정분을 지연 기록한다. 공유 라이브러리를 여러 프로세스가 한 벌의 물리 코드로 공유하는 것, demand zeroing으로 새 힙 페이지를 0으로 채워진 공용 프레임에 매핑했다가 쓰기 시점에만 실제 프레임을 할당하는 것 모두 같은 원리다. 이처럼 가상 메모리는 보호·공유·지연 할당이라는 세 축으로 시스템 효율을 끌어올린다.

다. 유효 접근 시간과 성능 민감도

요구 페이징의 성능은 유효 접근 시간(EAT)으로 정량화된다. 페이지 폴트율을 p, 메모리 접근시간을 ma, 폴트 처리시간을 pft라 하면 EAT = (1-p)×ma + p×pft이다. 예컨대 ma=100ns, pft=8ms(8,000,000ns)일 때, 폴트율이 단 0.1%(p=0.001)만 되어도 EAT ≈ 100×0.999 + 8,000,000×0.001 ≈ 8,100ns로, 폴트가 없을 때의 약 80배로 치솟는다. 성능 저하를 10% 이내로 묶으려면 폴트율을 약 1/800,000 이하로 유지해야 한다는 계산이 나온다. 이 극단적 민감도가 "폴트를 최대한 줄이는" 교체 알고리즘과 지역성 확보가 왜 사활적인지를 수치로 보여 준다.

3. 페이지 교체 알고리즘

물리 메모리가 가득 찬 상태에서 새 페이지를 올리려면 기존 페이지 하나를 내보내야 한다. 목표는 곧 다시 쓰일 페이지는 남기고, 당분간 안 쓰일 페이지를 내보내 폴트율을 최소화하는 것이다. 아래는 대표 알고리즘의 의사결정 흐름이다.

flowchart LR
    REQ["페이지 교체 필요"] --> OPT["OPT: 미래 최장기간<br/>미사용 페이지 교체"]
    REQ --> FIFO["FIFO: 가장 먼저<br/>들어온 페이지 교체"]
    REQ --> LRU["LRU: 가장 오래<br/>참조 안 된 페이지 교체"]
    REQ --> CLOCK["Clock(2차 기회):<br/>참조비트 0을 교체"]
    OPT -.->|"구현 불가, 이론적 하한"| BENCH["성능 비교 기준"]
    FIFO -.->|"Belady 역설 가능"| SIMPLE["단순하나 비효율"]
    LRU -.->|"지역성 반영, 구현 비용"| GOOD["준최적 근사"]
    CLOCK -.->|"LRU 근사, 저비용"| REAL["실무 채택"]

가. OPT(최적 교체)와 이론적 하한

OPT(Optimal, Belady 알고리즘)는 "앞으로 가장 오랫동안 참조되지 않을 페이지"를 교체한다. 미래 참조열을 알아야 하므로 실제 구현은 불가능하지만, 달성 가능한 최소 폴트 수의 이론적 하한을 제공해 다른 알고리즘의 성능을 평가하는 잣대로 쓰인다. 예를 들어 참조열 7 0 1 2 0 3 0 4 2 3 0 3 2를 프레임 3개로 돌리면 OPT는 FIFO·LRU보다 적은 폴트로 처리되며, 실무 알고리즘이 OPT에 얼마나 근접하는가가 설계 품질의 척도가 된다.

나. FIFO와 Belady의 역설

FIFO는 가장 먼저 적재된 페이지를 교체한다. 구현은 단순하나, "오래전에 올라왔지만 계속 쓰이는 페이지"까지 내보내는 맹점이 있다. 더 치명적인 것은 Belady의 역설(Belady's Anomaly)로, 프레임 수를 늘렸는데 오히려 폴트가 증가하는 비직관적 현상이 FIFO에서 나타난다. 참조열 1 2 3 4 1 2 5 1 2 3 4 5는 프레임 3개일 때보다 4개일 때 폴트가 더 많아지는 고전적 반례다. 이는 FIFO가 지역성을 전혀 반영하지 못함을 보여주며, 스택 알고리즘 성질을 갖는 LRU·OPT에서는 이 역설이 발생하지 않는다.

다. LRU와 그 근사

LRU(Least Recently Used)는 "가장 오래 참조되지 않은 페이지"를 교체한다. 과거의 참조 패턴이 가까운 미래에도 이어진다는 지역성 가정에 근거해 OPT에 근접한 성능을 내지만, 정확한 LRU는 매 참조마다 타임스탬프를 갱신하거나 참조 순서 리스트를 유지해야 해 하드웨어 비용이 크다. 그래서 현실에서는 근사 기법을 쓴다. 대표가 Clock(2차 기회) 알고리즘으로, 프레임을 원형으로 배열하고 참조비트를 검사해 1이면 0으로 지우고 넘어가(한 번 더 기회), 0을 만나면 교체한다. 수정비트를 함께 보는 향상된 Clock은 "참조 안 됨+깨끗함" 페이지를 우선 교체해 write-back까지 아낀다. 리눅스·윈도우 등 실제 OS는 이 Clock 계열에 다단계 LRU 리스트(active/inactive)와 노화(aging)를 결합한 변형을 쓴다.

아래 표는 대표 알고리즘을 성능·비용·특성으로 비교한다. 표만으로는 "왜"가 드러나지 않으므로, 차이의 원인을 함께 읽어야 한다.

알고리즘 교체 기준 폴트 성능 구현 비용 Belady 역설 실무 채택
OPT 미래 최장 미사용 최적(하한) 구현 불가 없음 평가 기준용
FIFO 적재 순서 나쁨 매우 낮음 발생 거의 안 씀
LRU 최근 미사용 우수 높음(HW) 없음 근사형만
Clock 참조비트 순회 양호(LRU 근사) 낮음 없음(근사) 널리 사용
LFU 참조 빈도 최소 상황 의존 중간 가능 캐시 등 제한적

성능 차이의 뿌리는 "얼마나 미래를 잘 예측하느냐"에 있다. FIFO는 적재 시점만 볼 뿐 사용 패턴을 무시해 예측력이 없고, LRU는 "최근 썼으면 곧 또 쓴다"는 지역성으로 미래를 근사하므로 강하다. Clock은 LRU의 예측력을 참조비트 한 개로 저렴하게 흉내 내 성능과 비용의 균형점을 잡았기에 실무를 지배한다. LFU는 장기 인기 페이지에 강하나, 초기에 반짝 많이 쓰이고 버려진 페이지가 높은 빈도수 때문에 눌러앉는 캐시 오염 문제가 있어 노화 기법과 함께 써야 한다.

라. 수치 비교 예시 — 같은 참조열, 다른 결과

알고리즘 차이를 체감하려면 동일 조건에서 폴트 수를 직접 세어 보는 것이 효과적이다. 프레임 3개, 참조열 2 3 2 1 5 2 4 5 3 2 5 2를 가정하자. FIFO는 적재 순서만 보므로 뒤에서 다시 쓰일 페이지(2)를 무심코 내보내 폴트가 많아지고, LRU는 최근 참조된 2·5를 보존해 폴트를 줄이며, OPT는 미래를 알고 가장 늦게 쓰일 페이지를 내보내 최소 폴트를 낸다. 일반적으로 이 참조열에서 폴트 수는 OPT < LRU ≤ FIFO 순서로 나타나, OPT가 제시한 하한에 LRU가 가깝고 FIFO가 가장 뒤처진다는 교과서적 서열이 재현된다. 핵심은 같은 메모리 용량(프레임 수)에서도 교체 정책만으로 폴트율이 크게 달라진다는 점이며, 2절의 EAT 민감도와 결합하면 이 폴트 수 차이가 곧 체감 성능의 수십 배 차이로 증폭될 수 있다.

이 서열이 항상 고정인 것은 아니다. 참조열에 뚜렷한 지역성이 없고 무작위에 가까우면 어떤 알고리즘이든 OPT에 크게 못 미치며, FIFO가 운 좋게 LRU와 비슷해지거나 Belady 역설로 역전되는 경우도 생긴다. 즉 교체 알고리즘의 우열은 참조 패턴에 의존하므로, 설계자는 대상 워크로드의 실제 트레이스로 폴트율을 측정해 정책을 고르는 것이 원칙이다.

실무 교체 정책은 여기서 한 걸음 더 나아가 스캔(scan) 저항성까지 고려한다. 대용량 파일을 한 번만 순차 읽는 작업은 방대한 페이지를 LRU 최상단에 밀어 넣어 정작 자주 쓰이는 페이지를 몰아내는데, 이를 막기 위해 리눅스는 새로 들어온 페이지를 바로 active로 승격하지 않고 inactive 리스트에서 재참조를 확인한 뒤 승격하는 2단계 승격 구조를 둔다. 데이터베이스 버퍼 풀의 LRU-K·2Q·ARC 같은 정책도 "한 번 쓴 것"과 "여러 번 쓴 것"을 분리해 순차 스캔이 캐시를 오염시키지 못하게 하는, 같은 문제의식의 산물이다.

4. 프레임 할당과 스래싱 — 교체만으로 부족한 이유

가. 프레임 할당 정책

교체 알고리즘이 아무리 좋아도, 프로세스에 주어진 프레임 수 자체가 작업집합보다 작으면 폴트가 폭증한다. 프레임 할당은 고정 할당(균등·비례)과 가변 할당으로 나뉘며, 교체 범위를 자기 프레임으로 한정하는 지역 교체와 전체에서 뺏는 전역 교체로도 구분된다. 전역 교체는 활발한 프로세스에 프레임을 몰아줄 수 있으나, 한 프로세스의 폴트가 남의 프레임을 빼앗아 연쇄 성능 저하를 부를 수 있다.

할당 방식의 선택은 공정성과 효율의 긴장을 그대로 드러낸다. 균등 할당은 모든 프로세스에 같은 수의 프레임을 주어 단순하지만, 작은 프로세스는 프레임이 남아돌고 큰 프로세스는 부족해진다. 비례 할당은 가상 주소 공간 크기에 비례해 나눠 이를 완화하지만, "크기가 크다고 활발히 쓰는 것은 아니다"라는 함정이 있다. 그래서 현대 OS는 폴트 거동을 보고 실시간으로 조절하는 가변 할당+전역 교체를 기본으로 삼되, 한 프로세스의 폭주가 전체를 끌어내리지 않도록 cgroup 메모리 제한 같은 상한을 함께 둔다.

나. 스래싱과 작업집합 모델

이 문제의 극단이 스래싱(thrashing)이다. 다중 프로그래밍 수준을 과도하게 높이면 각 프로세스의 프레임이 작업집합 이하로 쪼그라들어, CPU가 일은 안 하고 페이지 교체(디스크 I/O)에만 매달리는 상태가 된다. 이때 CPU 이용률을 높이려고 프로세스를 더 올리면 스래싱이 가속되는 악순환에 빠진다. 해법은 작업집합 모델(Working Set Model)로, 최근 Δ 시간 윈도우 동안 참조된 페이지 집합(WS)을 프로세스가 필요로 하는 프레임으로 보고, 모든 프로세스 WS 크기의 합이 물리 프레임을 넘지 않도록 다중 프로그래밍 수준을 조절한다. 또 다른 접근인 PFF(Page Fault Frequency)는 폴트율이 상한을 넘으면 프레임을 더 주고, 하한 아래로 떨어지면 회수해 폴트율을 목표 대역으로 제어한다. (※ 스래싱의 상세는 [[thrashing]], 메모리 분할 기법은 [[paging-vs-segmentation]] 참조.)

구체적 사례로, 메모리가 빠듯한 리눅스 서버에서 메모리 압박이 커지면 kswapd가 끊임없이 페이지를 회수하고 디스크 스왑 I/O가 치솟아 vmstat의 si/so 열이 급등하며 응답이 사실상 멈추는데, 이는 교과서의 스래싱이 운영 현장에서 그대로 재현되는 장면이다. 많은 조직이 이런 서비스에서 스왑을 제한하거나 cgroup 메모리 제한·OOM 정책을 함께 설계하는 이유가 여기에 있다.

5. 심화 — 현대 OS·하드웨어에서의 가상 메모리

가. 페이지 테이블·TLB의 확장

고전 이론은 여전히 유효하지만, 현대 시스템은 규모와 하드웨어 발전에 맞춰 가상 메모리를 크게 확장했다. 첫째, 다단계·역페이지 테이블이다. 64비트 주소 공간을 선형 페이지 테이블로 다루면 테이블 자체가 비현실적으로 커지므로, x86-64는 4~5단계 계층 페이지 테이블을 쓰고, 테이블 워크 비용을 줄이기 위해 다단계 TLB와 테이블 캐시를 둔다. 둘째, 거대 페이지(Huge Page, 2MB·1GB)로, 페이지 크기를 키워 TLB 항목 하나가 넓은 영역을 덮게 해 TLB 적중률을 높이고 테이블 워크 횟수를 줄인다 — 데이터베이스·JVM 대용량 힙·가상화에서 성능이 수 %~수십 % 개선된 사례가 보고된다. 셋째, 가상화의 중첩 페이징(EPT/NPT)으로, 게스트 가상→게스트 물리→호스트 물리의 2단계 변환을 하드웨어가 처리해 소프트웨어 섀도 페이지 테이블의 오버헤드를 제거했다.

이 확장의 숨은 비용은 주소 변환 자체의 지연이다. 5단계 페이지 테이블에서 TLB가 실패하면 최대 다섯 번의 메모리 접근이 필요하고, 중첩 페이징에서는 각 단계마다 호스트 변환이 또 끼어들어 최악의 경우 24회에 달하는 메모리 접근이 발생할 수 있다. 그래서 하드웨어는 페이지 테이블 상위 단계를 캐싱하는 전용 캐시(page-walk cache)를 두고, 소프트웨어는 거대 페이지와 메모리 접근 지역성으로 TLB 적중률을 끌어올려 이 비용을 상쇄한다 — 즉 "페이지 테이블을 키우는" 확장과 "변환을 빠르게 하는" 최적화는 늘 쌍으로 진행된다.

거대 페이지는 공짜가 아니다. 투명 거대 페이지(THP)가 메모리를 과도하게 선점하거나, 거대 페이지를 확보하려 커널이 작은 페이지들을 모으는 메모리 조각모음(compaction) 지연이 꼬리 지연을 악화시킨 사례도 보고된다. 그래서 데이터베이스 운영에서는 THP를 끄고 hugetlbfs로 명시적 거대 페이지만 쓰도록 권고하는 벤더가 많다 — 하드웨어 기능 하나를 켜고 끄는 결정조차 워크로드 특성과 계측 없이는 역효과를 낼 수 있음을 보여주는 실례다.

나. 티어드 메모리와 회수 정책의 진화

최근 동향도 활발하다. CXL 기반 메모리 확장·티어드 메모리(tiered memory)는 DRAM과 느린 원격 메모리를 계층화하고, OS가 핫·콜드 페이지를 자동 승강(promotion/demotion)시키는데 이는 본질적으로 "페이지 교체의 다계층화"다(관련: [[cxl]]). 리눅스의 MGLRU(Multi-Gen LRU)는 전통적 active/inactive 2단계 LRU를 여러 세대로 확장해 대규모 메모리에서 회수 결정의 정확도와 효율을 높인 2022년 이후의 대표 개선이다. 또한 Copy-on-Write·demand zeroing·메모리 압축(zswap/zram)은 모두 가상 메모리 계층에서 물리 메모리를 절약하는 기법으로, 컨테이너 밀집 환경의 집적도를 끌어올린다.

특히 메모리 압축은 디스크 스왑의 대안으로 주목받는다. 콜드 페이지를 느린 디스크로 내보내는 대신 CPU로 압축해 메모리 안에 보관(zram·zswap)하면, 디스크 I/O 없이 유효 메모리를 늘릴 수 있다. 안드로이드가 제한된 RAM에서 다수의 앱을 백그라운드에 유지하는 비결이 바로 zram이며, 쿠버네티스 노드에서도 OOM Kill을 줄이려 압축 스왑을 켜는 운영이 늘고 있다. 이는 "페이지를 어디에 어떤 형태로 둘 것인가"라는 가상 메모리의 본질적 질문이 디스크·압축·원격 메모리라는 다양한 백킹 스토어로 확장되고 있음을 보여 준다.

6. 고려사항 및 시사점(기술사 관점)

  • 적용 전략 — 워크로드별 정책 선택: 지연 민감 서비스(웹·DB)는 스왑을 억제하고 거대 페이지·충분한 작업집합 프레임을 확보해 폴트를 구조적으로 차단해야 하고, 배치·분석 워크로드는 메모리 오버커밋과 티어드 메모리를 활용해 집적도를 높이는 식으로 목적에 맞는 메모리 정책을 분리 설계해야 한다. 단일 최적 설정은 없으며 참조 지역성 분석이 선행되어야 한다.
  • 트레이드오프 관리: 페이지 크기는 내부 단편화(크게)와 TLB 효율(크게)의 균형, 오버커밋은 집적도(높게)와 OOM 위험(높게)의 균형, 전역/지역 교체는 전체 효율과 프로세스 간 격리의 균형점이다. 이들 상충을 vmstat·perf·폴트율로 정량 측정해 튜닝하는 역량이 요구된다.
  • 관측·검증 체계의 제도화: 가상 메모리 품질은 평균이 아니라 폴트율·스왑 I/O·TLB 미스율·메이저 폴트 분포로 드러나므로, 이를 상시 계측해 SLO와 연동하고 스래싱 징후를 조기 경보하는 관측 체계가 없으면 성능 튜닝은 근거를 잃는다.
  • 용량 산정과의 연계: 가상 메모리는 물리 메모리 초과 사용을 허용하지만 그것이 무한한 메모리를 뜻하지는 않는다. 작업집합의 합이 물리 메모리를 넘는 순간 성능이 비선형으로 붕괴하므로, 서버·컨테이너 용량 산정 시 RSS·작업집합 기반의 실측 수요를 근거로 메모리를 배분하고 스왑을 안전망으로만 쓰는 설계 원칙이 필요하다.
  • 보안·격리 연계: 가상 주소 격리는 프로세스 보호의 토대이지만, Meltdown·Spectre 같은 투기적 실행 부채널은 주소 변환·TLB 경로를 악용했다(관련: [[speculative-execution-branch-prediction]]). 커널 페이지 테이블 격리(KPTI) 등 완화책이 성능을 희생시키므로, 메모리 관리 설계는 이제 보안-성능 트레이드오프까지 함께 다뤄야 한다.
  • 설계 원칙으로서의 지역성 확보: 교체 알고리즘을 아무리 정교화해도 프로그램 자체의 참조 지역성이 나쁘면 폴트를 막을 수 없다. 자료구조의 메모리 배치(배열 vs 연결 리스트), 반복문의 접근 순서(행 우선 vs 열 우선), 데이터 지향 설계 등 응용 수준의 지역성 최적화가 OS 메모리 관리와 짝을 이뤄야 비로소 성능이 완성되며, 기술사는 하부 메커니즘과 상부 설계를 함께 조망할 수 있어야 한다.
  • 전망과 연계 기술: CXL 티어드 메모리·MGLRU·메모리 압축은 "느린 대용량 계층을 교체 정책으로 관리"하는 방향으로 수렴하며, 향후 가상 메모리는 DRAM을 넘어 이종 메모리 계층 전체를 관장하는 데이터 배치 엔진으로 진화할 것이다. 클라우드 자원 관리([[finops]])·컨테이너 밀집도와 직접 맞닿아 있어, OS 메모리 원리의 이해는 인프라 비용 최적화의 토대가 된다.

참고자료


한 줄 요약: 가상 메모리는 요구 페이징으로 필요한 페이지만 적재해 물리 메모리를 초월한 주소 공간과 프로세스 격리를 제공하는 기법으로, 폴트율에 극도로 민감하기에 OPT·FIFO·LRU·Clock 등 교체 알고리즘과 작업집합 기반 프레임 할당으로 스래싱을 막으며, 현대에는 거대 페이지·중첩 페이징·MGLRU·CXL 티어드 메모리로 확장되고 있다.