페이지 부재 빈도 (PFF, Page-Fault Frequency) 모델
핵심 인사이트 (3줄 요약)
- 본질: 페이지 부재 빈도(PFF) 모델은 스래싱을 막기 위해 복잡하게 과거를 추적하는 워킹 셋(Working Set) 모델 대신, 단순히 "초당 페이지 폴트(Page Fault)가 몇 번 터지는가?"의 빈도(Frequency)만을 측정하여 상한선과 하한선으로 램 할당을 조절하는 직관적 동적 할당 기법이다.
- 가치: 앱의 폴트율이 상한선(Upper Bound)을 넘으면 램 프레임을 더 퍼주고, 하한선(Lower Bound) 밑으로 떨어지면 남는 램을 빼앗아 회수함으로써, 시스템 전체의 페이지 폴트율을 쾌적한 중간 지점(Plateau)에 강제로 머물게 하는 극강의 가성비를 자랑한다.
- 융합: 페이지 테이블을 쉴 새 없이 긁어야 하는 오버헤드를 0으로 만들고, 오직 인터럽트(Page Fault)가 발생할 때만 OS가 개입하므로 전역 교체(Global Replacement)의 부작용을 통제하는 리눅스 스케줄러의 핵심 뼈대로 융합되었다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
-
개념: PFF(Page-Fault Frequency)는 프로세스가 실행되면서 일으키는 페이지 폴트의 '속도(Rate, 빈도)'에 직접적으로 반응하는 피드백 루프(Feedback Loop) 제어 모델이다. 폴트율이 미친 듯이 높아지면 램이 쪼들린다는 뜻이니 방을 늘려주고, 폴트율이 0에 가까우면 방이 남아돈다는 뜻이니 램을 뺏어버리는 상/하한선(Watermark) 제어 방식이다.
-
필요성: 이전 장에서 배운 '워킹 셋(Working Set)' 모델은 완벽했다. 하지만 OS가 매 클럭마다 윈도우 $\Delta$(과거 1만 번의 기록)를 스캔해서 집합을 갱신하는 짓은 하드웨어 오버헤드가 너무 무거워 실전에선 짐 덩어리였다. 공학자들은 "과거 기록을 왜 다 살펴봐? 그냥 지금 애가 아파서(Page Fault) 소리 지르는 횟수만 세어보면, 램이 모자란 지 남는지 견적이 딱 나오잖아?"라는 통쾌한 우회로를 찾았다. 증상(Fault)만 보고 약(RAM)을 처방하는 초고속 돌팔이(?) 명의의 탄생이다.
-
💡 비유: PFF는 보일러 온도 조절기의 상한/하한 센서와 같다. 워킹 셋 모델이 바깥 날씨, 바람 속도, 방 크기를 복잡하게 수식으로 계산해서 보일러를 트는 방식이라면, PFF는 그냥 벽에 온도계 하나 딱 달아놓는 것이다. 온도가 18도(하한선, 램 부족) 밑으로 떨어져서 춥다고 덜덜 떨면(폴트 폭발) 보일러를 팡팡 틀어주고(램 추가), 온도가 26도(상한선, 램 낭비)를 넘어서 더워지면 즉각 보일러를 꺼서 가스비(남는 램)를 아끼는 극한의 실용주의 시스템이다.
-
등장 배경 및 오버헤드 혐오:
- 워킹 셋의 이상과 현실: 수학적으론 완벽했으나, 런타임에 그 집합을 계산하느라 CPU가 다 늙어버림.
- Page Fault의 재해석: 폴트(에러) 자체가 바로 앱의 램 부족 상태를 알려주는 가장 훌륭하고 정직한 시그널임을 깨달음.
- Direct Feedback Control: 원인을 분석하지 말고, 결과(Fault Frequency)만 보고 램 배급량을 조절하는 직접 통제(PID 제어) 방식을 채택함.
┌────────────────────────────────────────────────────────────────────────┐
│ PFF (페이지 부재 빈도) 제어 알고리즘의 동작 런타임 시각화 │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ [ Y축: 페이지 폴트 발생 빈도 (Rate) / X축: 할당된 프레임 수 ] │
│ │
│ 🚨 상한선 (Upper Bound) ------------------ (예: 1초에 100번) │
│ ▲ │
│ │ (이 구역은 스래싱 직전! 램이 너무 쪼들리는 지옥 상태) │
│ │ 🟢 OS 처방: "얘한테 빨리 물리 프레임을 더 줘서 살려내!" │
│ │
│ 🌈 쾌적 구간 (Plateau) -------------------- (가장 완벽한 타협점) │
│ │ (폴트가 1초에 5~50번 터짐. 살짝 끊기지만 봐줄 만함) │
│ │ 🟢 OS 처방: "딱 좋네. 램 안 주고 안 뺏고 그대로 유지(Hold)!" │
│ │
│ 📉 하한선 (Lower Bound) ------------------ (예: 1초에 1번 미만) │
│ ▼ │
│ │ (폴트가 아예 안 터짐! 램이 과도하게 커서 썩어 넘치는 낭비 상태)│
│ │ 🔴 OS 처방: "배가 불렀네! 얘 프레임 당장 뺏어서 남 줘!(Trim)" │
└────────────────────────────────────────────────────────────────────────┘
[다이어그램 해설] 이것이 PFF의 모든 것이다. OS는 복잡한 수식을 던져버리고 오직 프로세스마다 Fault Counter 타이머 하나만 달아두었다. 이 카운터가 상한선을 뚫으면 램을 들이붓고, 하한선을 뚫고 내려가면 가차 없이 램을 뜯어낸다. 램을 뜯어내면 폴트가 터지면서 다시 위로 올라올 텐데, 결국 프로세스의 상태는 상한선과 하한선 사이의 '쾌적 구간'에서 지그재그로 진동(Oscillation)하며 완벽한 균형을 유지하게 된다.
- 📢 섹션 요약 비유: 아이에게 용돈을 줄 때, 아이가 가계부를 써오게(워킹 셋) 시키는 건 부모도 아이도 피곤합니다. 그냥 "돈 떨어져서 엄마한테 전화(Page Fault)하는 횟수"만 세어보는 겁니다. 하루에 10번씩 돈 달라고 전화하면 용돈을 확 올려주고(상한선), 한 달 내내 돈 달란 소리가 없으면 용돈이 남아도는 거니 용돈을 싹둑 깎아버리는(하한선) 아주 편하고 확실한 용돈 통제술입니다.
Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)
프레임 회수와 추가의 딜레마 (OOM 방어)
PFF 알고리즘이 완벽히 작동하려면 **'빈방(Free Frame)의 여유분'**이 필수다.
- 상한선 돌파 (폴트 폭발): 어떤 프로세스의 PFF가 상한선을 뚫어 램을 더 줘야 한다. 그런데 시스템 전체에 남는 물리 램 빈방이 단 한 개도 없다면?
- 워킹 셋과의 공통점 (강제 수면, Suspend): OS는 당황하지 않는다. 램이 없다고 억지로 남의 걸 뺏어 주면 연쇄 스래싱이 터지는 걸 알고 있기 때문이다. 그래서 OS는 눈물을 머금고, 특정 프로세스 하나를 찝어서 아예 일시 정지(Suspend/Swap-out) 시켜버린다. 기절한 프로세스가 뱉어낸 엄청난 양의 램 프레임을 회수하여, 상한선을 뚫고 헐떡이던 놈들에게 쫙 나눠주어 스래싱을 완벽히 방어한다.
폴트 간격 (Time between faults) 측정 흑마술
OS 커널이 "초당 몇 번?"을 세는 것도 사실 타이머 오버헤드가 있다. 실무 커널은 이걸 **두 폴트 사이의 시간 간격($t_{current} - t_{last}$)**으로 계산한다.
-
1번 폴트가 터진 후, 다음 2번 폴트가 터질 때까지 걸린 시간이 너무 짧으면(예: 0.001초) -> 빈도가 높은 것(상한선 돌파). 램을 추가(Add)한다.
-
2번 폴트와 3번 폴트 사이의 시간이 엄청 길다면(예: 10초) -> 빈도가 낮은 것(하한선 돌파). 램이 낭비되고 있으니 프레임들을 뺏어낸다(Trim). 이처럼 인터럽트가 터진 그 찰나의 순간에만 시계 뺄셈 연산 1번으로 모든 상태를 결정해 버리므로 CPU 낭비(Overhead)가 말 그대로 '0'에 수렴한다. 워킹 셋 모델을 철저히 무너뜨린 PFF의 강력한 무기다.
-
📢 섹션 요약 비유: 의사가 환자의 건강을 체크할 때, 환자가 먹은 모든 식단과 운동량(워킹 셋)을 분석하려면 며칠이 걸립니다. 하지만 그냥 환자의 맥박 수(폴트 간격)를 딱 1초만 짚어보고, 맥박이 미친 듯이 뛰면 약(램)을 투여하고, 너무 천천히 뛰면 약을 줄이는(PFF) 방식은 0.1초 만에 진단이 끝나는 기적의 응급처치입니다.
Ⅲ. 융합 비교 및 다각도 분석
비교 1: 워킹 셋(Working-Set) vs 페이지 부재 빈도(PFF)
스래싱 방어의 두 거두가 맞붙는 면접 단골 비교다.
| 평가 기준 | 워킹 셋 (Working Set) 모델 | 페이지 부재 빈도 (PFF) 모델 |
|---|---|---|
| 통제 철학 | **과거(원인)**를 분석해 미래를 대비함 | **현재 증상(결과)**만 보고 즉각 때려잡음 |
| 관찰 대상 | 매 메모리 참조(Reference)마다 윈도우 스캔 | 오직 Page Fault가 터지는 순간에만 시간 계산 |
| 운영체제 부하 | 매우 무거움 (항상 감시해야 함) | 매우 가벼움 (폴트 날 때만 덧뺄셈 1번) |
| 반응 속도 | 국면 전환(Phase Shift) 시 살짝 반응이 느림 | 폴트가 터지는 즉시 프레임을 꽂아주므로 반응성 극강 |
| 현실 채택 | 윈도우(Windows)의 메모리 관리 뼈대 | 리눅스(Linux)의 커널 스래싱 방어 뼈대 |
맹점: 국면 전환 (Phase Transition)에서의 PFF 헛발질
PFF는 워킹 셋보다 멍청하기 때문에 치명적인 약점을 하나 가지고 있다.
- 프로그램이
초기화(Init)단계를 끝내고본게임(Main)으로 훅 넘어가는 국면 전환(Phase Transition) 순간을 생각해 보자. - 코드가 완전히 바뀌었으니 당연히 무지막지한 Page Fault 소나기가 펑펑 터진다.
- PFF의 오판: PFF는 이걸 보고 "어! 램이 엄청 모자라구나!" 착각하고, 램 프레임을 막 1,000장씩 미친 듯이 퍼다 부어준다.
- 진실: 사실 램이 모자란 게 아니라 그냥 새 코드를 읽는 자연스러운 현상일 뿐이다. 오히려 옛날
Init()시절에 쓰던 램 1,000장은 다 쓰레기가 되었으므로 램을 뺏어야 정상이다. PFF는 증상만 볼 뿐 내용물(과거)은 보지 못하므로, 이 찰나의 순간에 램을 과잉 지급하여 시스템 메모리를 낭비하는 맹점을 노출한다.
┌──────────┬────────────┬────────────┬────────────────────────────────┐
│ 모델 │ 안정 상태(루프)│ 국면 전환(Phase)│ CPU 낭비율 │
├──────────┼────────────┼────────────┼────────────────────────────────┤
│ Working Set│ 🟢 완벽 배분 │ 🟢 옛날 램 칼같이 회수│ 🔴 너무 무거움 │
│ PFF │ 🟢 완벽 배분 │ 🔴 쓸데없이 램 퍼줌 │ 🟢 깃털처럼 가벼움 │
└──────────┴────────────┴────────────┴────────────────────────────────┘
[매트릭스 해설] 완벽한 알고리즘은 없다. PFF는 국면 전환 시 램을 조금 낭비하긴 하지만, 어차피 몇 초 뒤에 하한선(Lower Bound) 밑으로 떨어지며 OS가 낭비된 램을 귀신같이 다시 회수(Trim)해 간다. 잠깐의 낭비를 허용하더라도 평상시의 압도적인 가벼움을 택한 것이 현대 OS의 결론이다.
- 📢 섹션 요약 비유: PFF 의사는 환자가 기침(폴트)을 심하게 하면 무조건 폐렴약(램 추가)을 왕창 줍니다. 알고 보니 환자가 그냥 매운 떡볶이(국면 전환)를 먹어서 기침한 거였는데도 말이죠. 약 낭비는 좀 심하지만, 어쨌든 1초 만에 약을 줘서 사람을 살리는 덴 최고입니다.
Ⅳ. 실무 적용 및 기술사적 판단 (Strategy & Decision)
실무 시나리오: 리눅스의 kswapd 워터마크(Watermark) 튜닝
리눅스 커널은 PFF의 상하한선 개념을 응용하여 전체 램 잔고를 통제하는 kswapd 데몬을 굴린다.
- 커널 파라미터 (
vm.min_free_kbytes):- 서버 엔지니어는 램이 고갈되어 PFF가 폭발(스래싱)하는 것을 막기 위해, 시스템 전체의 최소 빈방 개수를 수동으로 설정한다.
- 세 가지 워터마크 (High, Low, Min):
- High 선: 램이 넉넉함. kswapd는 깊은 잠을 잔다.
- Low 선 (하한선 돌파): 앱들이 램을 쳐먹어 빈방이 Low 밑으로 떨어지면, kswapd가 부스스 깨어난다. 그리고 PFF가 낮은(램 남아도는) 놈들의 램을 툭툭 뺏어서 빈방을 High 선까지 다시 채워놓고 다시 잔다 (Background Reclaim).
- Min 선 (스래싱 임계점): 갑자기 DB가 미쳐서 램을 쓸어 담아 빈방이 Min 밑으로 박살 났다! kswapd로는 수습 불가. 모든 유저 앱을 강제 스탑 시키고, 앱들이 직접 자기 램을 뱉어내게 만드는 가혹한 **Direct Reclaim (강제 폴트 렉)**이 터진다.
- 실무적 결론: PFF와 워터마크의 조합은 리눅스 서버가 죽지 않고 버티게 해주는 호흡기다. 만약 서버에 렉이 툭툭 걸린다면
min_free_kbytes를 너무 쪼잔하게 잡아 OS가 대처할 시간을 못 벌었기 때문이므로 이 값을 올려 여유를 줘야 한다.
안티패턴: 너무 좁은 상하한선 간격 (Ping-Pong 현상)
OS 설계자가 PFF의 상한선을 초당 50번, 하한선을 초당 40번으로 너무 좁게 잡아버렸다고 치자. 앱의 폴트율은 45번을 중심으로 계속 미세하게 요동치는데, 51번이 되면 OS가 램을 주고, 39번이 되면 OS가 램을 뺏어버린다. 앱은 0.1초마다 램을 받았다 뺏겼다를 무한 반복하며 OS를 핑퐁(Ping-Pong) 게임의 늪에 빠뜨려 커널 CPU 낭비가 100%에 도달하게 된다. 상한선과 하한선 사이의 **버퍼 구간(Plateau)**은 아주 넓고 자비롭게 세팅되어야만 시스템이 흔들리지 않는다.
- 📢 섹션 요약 비유: 에어컨 온도를 24도에 맞췄는데, 24.1도가 되면 에어컨이 윙! 켜졌다가, 23.9도가 되면 히터가 윙! 켜지는 미친 시스템(간격 좁음)입니다. 에어컨과 히터가 1초마다 켜졌다 꺼지며 전기세가 폭발합니다. 26도 넘으면 에어컨, 18도 밑이면 히터를 켜도록 넓은 여유(버퍼)를 둬야 평화로운 집안이 됩니다.
Ⅴ. 기대효과 및 결론 (Future & Standard)
정량/정성 기대효과
| 구분 | 내용 |
|---|---|
| $O(1)$ 스래싱 감지 및 방어 | 수만 장의 과거 페이지를 탐색하는 O(N) 오버헤드 없이, 트랩 터질 때 타이머 뺄셈 한 번으로 램 부족 사태를 완벽 진단 |
| 동적 메모리 재분배의 실현 | 가변 분할/전역 교체가 유발하던 "가진 놈이 더 뺏는 마피아 현상"을 빈도 제어라는 공권력으로 억제하여 공평한 램 분배 달성 |
| 운영체제 스케줄러와의 결합 | PFF가 상한선을 뚫었는데 램이 없으면 즉각 스케줄러에 "얘 기절시켜(Suspend)!"라는 시그널을 보내어 시스템 뇌사를 하드캐리 방어 |
결론 및 미래 전망
페이지 부재 빈도 (PFF) 모델은 완벽함을 좇던 이론가(Working Set)들의 코를 납작하게 누르고, "시스템은 대충 증상만 보고 때려잡아도 기가 막히게 잘 굴러간다"는 엔지니어들의 거친 실용주의가 거둔 짜릿한 승리다. 과거(워킹 셋)를 기억하지 않고 오직 현재 터지고 있는 오류의 비명(Page Fault Rate)에만 귀 기울이는 이 알고리즘은, 현대 운영체제의 복잡한 자원 관리 철학을 가장 단순한 형태의 피드백 제어(Feedback Control)로 치환해 냈다. 향후 클라우드의 오토 스케일링(Auto-scaling) 기술이나 쿠버네티스의 HPA(수평 팟 자동 확장)가 CPU 사용률이나 에러 빈도를 보고 서버 대수를 늘렸다 줄였다 하는 뼈대 로직 또한, 정확히 이 1980년대의 PFF 상하한선 스위칭 철학의 거대한 확장판이라 볼 수 있다.
- 📢 섹션 요약 비유: 자율주행 자동차가 앞차와의 거리를 계산할 때 복잡한 뉴턴의 물리 공식과 10분 전의 속도 이력을 다 꺼내서 계산(워킹 셋)하다가 사고가 나느니, 그냥 앞차랑 가까워지면 브레이크 밟고 멀어지면 엑셀 밟는 아주 단순한 레이더 센서(PFF)만으로도 100km 고속 주행을 완벽하게 해내는 것과 같은 공학의 진리입니다.
📌 관련 개념 맵 (Knowledge Graph)
- 워킹 셋 모델 (Working Set Model) | PFF의 형님 격인 이론. 과거 $\Delta$ 시간 동안의 페이지 집합을 완벽히 계산하려다 렉에 치여 쓰러진 이상주의 모델
- 스래싱 (Thrashing) | PFF가 상한선 알람을 울리며 필사적으로 막아내려고 하는 시스템의 뇌사(무한 디스크 I/O) 상태
- 강제 수면 (Suspend) | PFF 상한선이 터졌는데 줄 램(Free Frame)이 없을 때, OS가 살기 위해 프로세스 하나를 기절시켜 램을 토해내게 만드는 궁극기
- 국면 전환 (Phase Transition) | PFF가 멍청하게 "램 모자라네!" 하고 헛발질(램 낭비)을 하게 만드는, 프로그램 실행 코드가 통째로 뒤바뀌는 찰나의 순간
- 전역 교체 (Global Replacement) | PFF와 융합되어, "빈도가 높으니 램을 더 줘라" 할 때 남의 램을 무자비하게 뺏어올 수 있는 깡패 같은 행동 대장
👶 어린이를 위한 3줄 비유 설명
- 페이지 부재 빈도(PFF)가 뭔가요? 엄마가 나한테 용돈을 줄 때, 복잡하게 용돈 기입장(과거 기록)을 보지 않고, 내가 "엄마 돈 떨어졌어!(페이지 폴트)"라고 소리치는 '횟수'만 세어보고 용돈을 조절하는 방법이에요.
- 어떻게 조절하나요? 내가 하루에 10번씩 돈 달라고 징징대면(상한선 돌파) "아이고 용돈이 엄청 모자라구나!" 하고 만 원을 확 더 얹어 줘요.
- 만약 내가 돈 달라고 안 하면요? 일주일 내내 한 번도 돈 달라고 안 하면(하한선 밑으로 떨어짐), 엄마가 눈치채고 "너 돈 남아도는구나?" 하며 내 지갑에서 오천 원을 슬쩍 빼서 동생을 줘버린답니다!