TT Lab
시작하기
배우기 러닝패스 코스

운영체제

요구 페이징과 스래싱 — 메모리가 모자랄 때 벌어지는 일

TT Lab 에서 이어서 보기

한 줄 요약

페이지를 필요할 때만 올리면 물리 메모리보다 큰 프로그램도 돌릴 수 있지만, 폴트 한 번의 비용이 메모리 접근보다 수만 배 비싸므로 폴트율이 조금만 올라도 시스템이 무너진다.

왜 이게 필요했나

프로그램 전체를 메모리에 올릴 필요는 없다. 오류 처리 코드처럼 거의 실행되지 않는 부분도 많고, 큰 배열의 일부만 실제로 쓰이는 경우도 흔하다. 필요한 시점에만 올리면(요구 페이징) 더 많은 프로세스를 동시에 돌릴 수 있고, 프로그램 시작도 빨라진다.

페이지 폴트 한 번이 치르는 값

유효 비트가 꺼진 페이지를 건드린 순간부터 그 명령어가 다시 실행되기까지를 세 토막으로 줄였다. 비싼 것은 가운데 토막이다.

  1. 트랩과 판정커널로 들어가 주소 범위 밖의 잘못된 접근인지, 아직 올리지 않은 페이지인지 가른다. 잘못된 접근이면 여기서 끝난다.
  2. 프레임 마련과 디스크 읽기빈 프레임이 없으면 희생 페이지를 고르고, 수정된 페이지라면 먼저 디스크에 쓴다. 그다음 필요한 페이지를 읽어 온다. 밀리초 단위의 비용이 여기서 나온다.
  3. 표 갱신과 재실행페이지 테이블을 고치고 폴트를 일으킨 명령어부터 다시 실행한다. 프로그램은 아무 일도 없었던 것처럼 이어 간다.

여기서 구분할 것 나노초 단위의 메모리 접근과 밀리초 단위의 폴트 처리는 수만 배 차이가 난다. 그래서 폴트율은 퍼센트가 아니라 몇십만 번에 한 번이라는 단위로 따진다.

잠깐, 예측해 보세요 메모리 접근 200ns, 폴트 처리 8ms 인 시스템에서 천 번에 한 번 폴트가 난다. 평균 접근 시간은 0.1% 쯤 느려질까?

설명 확인 · 채점 없는 자가 점검

아니다. 실효 접근 시간이 약 8,200ns 로 40배 느려진다. 폴트 한 번이 메모리 접근 4만 번의 값을 치르므로 드문 폴트가 평균을 지배한다.

근거 문서

어떻게 동작하나

페이지 테이블 항목에 유효 비트를 둔다. 유효하지 않은 페이지에 접근하면 페이지 폴트가 발생하고 다음 순서로 처리된다.

  1. 트랩이 걸려 커널로 진입한다.
  2. 잘못된 접근인지(주소 범위 밖) 아니면 아직 안 올린 것인지 판단한다.
  3. 빈 프레임을 찾는다. 없으면 희생 페이지를 골라 내보낸다. 그 페이지가 수정된 상태(dirty)면 먼저 디스크에 기록한다.
  4. 디스크에서 페이지를 읽어 프레임에 올린다.
  5. 페이지 테이블을 갱신하고, 폴트를 일으킨 명령어부터 다시 실행한다.

비용을 계산해 보면 무섭다. 메모리 접근이 200ns 이고 페이지 폴트 처리가 8ms 라고 하자. 폴트 확률이 p 일 때 실효 접근 시간은 (1 빼기 p) 곱하기 200 더하기 p 곱하기 8,000,000 이다.

페이지 교체 알고리즘의 성격도 알아 둘 만하다. 참조열 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1 에 프레임 3개를 주면 FIFO 는 폴트 15회, LRU 는 12회, 이론적 최적인 OPT 는 9회다. FIFO 에는 프레임을 늘렸는데 폴트가 늘어나는 벨래디의 이상현상까지 있다. 실무 시스템은 순수 LRU 대신 참조 비트를 이용한 클럭(second-chance) 알고리즘을 쓴다. LRU 에 가까운 성능을 훨씬 싼 비용으로 얻기 때문이다.

스래싱은 프레임이 부족해 폴트가 폭증하고, 그 때문에 CPU 가 놀고, 운영체제가 "한가하니 프로세스를 더 올리자"고 판단해 상황이 더 나빠지는 악순환이다. 대응은 워킹 셋(최근 일정 구간에서 실제로 참조된 페이지 집합)을 추적해 그만큼의 프레임을 보장하거나, 폴트율을 직접 모니터링해 프레임을 조절하는 것이다.

현장에서 만나는 모습

컨테이너에 메모리 제한을 걸었을 때 두 가지 결말이 있다. 스왑이 꺼져 있으면 OOM Killer 가 프로세스를 죽인다. 갑작스럽지만 원인은 명확하다. 스왑이 켜져 있으면 대신 스래싱이 시작된다. 프로세스는 살아 있는데 응답이 수십 배 느려지고, CPU 사용률은 낮은데 iowait 만 치솟는다. 죽는 편이 차라리 진단하기 쉽다는 말이 나오는 이유다. 쿠버네티스가 오랫동안 스왑을 끄도록 요구했던 배경에도 이 예측 불가능성이 있다.

같은 메모리 부족, 스왑 하나로 갈리는 결말

컨테이너가 메모리 한도에 닿은 같은 상황이다. 스왑이 있느냐에 따라 증상이 전혀 다르게 나타난다.

  • 스왑이 꺼져 있다되찾을 페이지가 바닥나면 OOM Killer 가 프로세스를 죽인다. 갑작스럽지만 종료 기록이 남아 원인이 곧바로 드러난다.
  • 스왑이 켜져 있다죽지 않고 페이지를 디스크로 내보냈다 다시 읽기를 되풀이한다. 프로세스는 살아 있는데 응답이 수십 배 느려지고 iowait 만 치솟는다.

여기서 구분할 것 CPU 사용률이 낮다고 한가한 것이 아니다. 스래싱 중인 시스템은 디스크를 기다리느라 CPU 가 논다. 이것을 여유로 보고 프로세스를 더 올리면 악순환이 된다.

잠깐, 예측해 보세요 응답이 갑자기 느려졌는데 CPU 사용률은 낮고 iowait 가 높다. 워커 프로세스를 더 띄우면 나아질까?

설명 확인 · 채점 없는 자가 점검

더 나빠진다. 스래싱이라면 모자란 것은 CPU 가 아니라 프레임이다. 프로세스를 늘리면 필요한 워킹 셋이 커져 폴트가 더 늘어난다. 줄이거나 메모리를 보장해야 한다.

근거 문서

이어지는 퀴즈에서 확인할 것

페이지 폴트 비용 계산을 직접 할 수 있는지, 스래싱이 왜 스스로를 강화하는 악순환인지 설명할 수 있는지 확인한다.