Foundry
운영체제
중급
핵심

페이지 교체 알고리즘

FIFO, LRU, LFU, Optimal 알고리즘

페이지 교체 알고리즘

물리 메모리가 가득 찼을 때, 어떤 페이지를 쫓아낼지 결정하는 알고리즘

주요 알고리즘

알고리즘기준특징
FIFO먼저 들어온 것단순, Belady 이상
LRU가장 오래 안 쓴 것성능 좋음, 구현 비용
LFU가장 적게 쓴 것빈도 기반
ClockLRU 근사실무 사용
OPT미래에 가장 늦게 쓸 것이론적 최적 (구현 불가)

FIFO (First In First Out)

프레임 3개, 참조: 1 2 3 4 1 2 5

[1]       → [1]
[1,2]     → [1,2]
[1,2,3]   → [1,2,3]
4 → 1 교체 → [4,2,3] 폴트!
1 → 2 교체 → [4,1,3] 폴트!
2 → 3 교체 → [4,1,2] 폴트!
5 → 4 교체 → [5,1,2] 폴트!

Belady 이상: 프레임 늘려도 폴트 증가 가능!

LRU (Least Recently Used)

프레임 3개, 참조: 1 2 3 4 1 2 5

[1]       → [1]
[1,2]     → [1,2]
[1,2,3]   → [1,2,3]
4 → 1이 가장 오래 전 → [4,2,3] 폴트
1 → 2가 가장 오래 전 → [4,1,3] 폴트
2 → 3이 가장 오래 전 → [4,1,2] 폴트
5 → 4가 가장 오래 전 → [5,1,2] 폴트

FIFO보다 일반적으로 성능 좋음

Clock 알고리즘 (Second Chance)

원형 버퍼 + 참조 비트

→ [1:1] → [2:1] → [3:0] → [4:1]
  ↑ 시계 바늘

교체 시:
1. 참조 비트 1 → 0으로 바꾸고 넘어감
2. 참조 비트 0 → 이 페이지 교체!

LRU 근사 + 오버헤드 적음
→ 실제 OS에서 많이 사용

비교

기준FIFOLRUClock
구현쉬움복잡중간
성능보통좋음좋음
오버헤드낮음높음낮음
Belady있음없음없음
실무드묾Redis 등Linux
면접에서 이렇게 나옵니다

Q.LRU 페이지 교체 알고리즘을 설명해주세요.

가장 오래 안 쓴 페이지를 내보내는 방식입니다. 최근에 쓴 것은 곧 또 쓸 것이라는 지역성 가정에 기댑니다.

참조열 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5 에 프레임 3개면 폴트가 10회입니다.

장점단점
지역성이 있는 실제 워크로드에서 잘 맞는다정확히 구현하려면 접근마다 기록해야 한다
프레임을 늘리면 폴트가 줄거나 같다그 기록 비용이 하드웨어 지원 없이는 크다

두 번째 장점이 중요합니다. LRU 는 프레임 n개일 때 담는 집합이 n+1개일 때의 부분집합이라, 메모리를 늘렸는데 폴트가 늘어나는 일이 없습니다. FIFO 는 이 성질이 없어 그런 역전이 생깁니다.

흔한 실수: 실제 OS 가 LRU 를 그대로 쓴다고 답하는 것. 매 접근마다 순서를 갱신하는 비용이 커서, 참조 비트를 이용한 근사 방식을 씁니다.

Q.FIFO의 Belady 이상(anomaly)이란?

프레임을 늘렸는데 폴트가 오히려 늘어나는 현상입니다.

참조열 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5 로 실측하면 이렇습니다.

정책3프레임4프레임
FIFO폴트 9회폴트 10회
LRU폴트 10회폴트 8회

FIFO 에서 생기는 이유는 들어온 순서만 보기 때문입니다. 프레임 수가 바뀌면 내보내는 대상이 완전히 달라져, 3프레임에서 담고 있던 집합이 4프레임의 부분집합이 아닙니다.

LRU 는 "가장 오래 안 쓴 것"이 기준이라 이 포함 관계가 유지되고, 그래서 역전이 생기지 않습니다.

흔한 실수: 이 현상을 이론적 호기심으로만 보는 것. "메모리를 늘렸는데 느려졌다"는 실무 증상의 원인이 될 수 있고, 그때 교체 정책이 순서 기반인지 확인하는 것이 진단 경로입니다.

Q.LRU를 효율적으로 구현하는 방법은?

정확한 LRU 는 비싸므로 근사합니다.

방식내용비용
이중 연결 리스트와 해시접근 시 맨 앞으로 옮긴다정확하지만 접근마다 갱신
참조 비트 (둘러보기)하드웨어가 접근 시 비트를 켠다. 시계 방향으로 돌며 비트가 0인 것을 내보낸다매우 싸다
참조 비트 여러 개주기적으로 비트를 옮겨 대략적인 최근성을 기록조금 더 정확하다
수정 비트 함께수정 안 된 페이지를 우선 내보낸다디스크 쓰기를 줄인다

애플리케이션 캐시(LRU 캐시)는 첫 번째를 씁니다. 접근 횟수가 상대적으로 적고 정확성이 중요하기 때문입니다.

운영체제는 두 번째를 씁니다. 메모리 접근은 초당 수억 번이라 매번 리스트를 조작할 수 없고, 하드웨어가 켜주는 비트 하나로 근사하는 것이 현실적입니다.

흔한 실수: 운영체제와 애플리케이션 캐시를 같은 방식으로 설명하는 것. 접근 빈도가 몇 자릿수 달라 선택이 갈립니다.

Q.실제 OS에서 사용하는 페이지 교체 알고리즘은?

LRU 근사와 사용 빈도를 섞은 방식을 씁니다.

운영체제방식
리눅스활성과 비활성 두 목록을 두고 참조 비트로 오간다. 최근성과 빈도를 함께 본다
윈도우작업 집합 기반. 프로세스별로 유지할 페이지 수를 관리한다
공통참조 비트를 이용한 둘러보기 계열

리눅스의 두 목록 구조가 해결하는 문제가 있습니다. 큰 파일을 한 번 훑으면 그 페이지들이 캐시를 전부 밀어내는데, 새로 들어온 페이지를 비활성 목록에 두고 다시 참조돼야 활성으로 올려 이것을 막습니다.

수정 여부도 함께 봅니다. 수정된 페이지는 내보낼 때 디스크에 써야 하므로, 같은 조건이면 수정 안 된 쪽을 먼저 고릅니다.

흔한 실수: 교과서의 LRU 나 최적 알고리즘을 실제 구현이라고 답하는 것. 최적 알고리즘은 미래를 알아야 해서 비교 기준으로만 씁니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

더 깊이 공부하기

읽었으면 문제로 확인해보세요

운영체제 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.