Thrashing과 OOM Killer — 메모리 관리의 핵심 메커니즘

2025. 10. 29. 19:29개념 공부

목차

  1. Thrashing (스왑 폭주 현상)
  2. Working Set Model (작업 집합 모델)
  3. PFF (Page Fault Frequency)
  4. Admission Control (승인 제어)
  5. Linux OOM Killer

1. Thrashing (스왑 폭주 현상)

1.1 Thrashing이란?

Thrashing은 운영체제의 멀티태스킹 환경에서 발생하는 심각한 성능 저하 현상입니다. 프로세스들이 요구하는 메모리가 사용 가능한 물리 메모리를 초과할 때, 시스템은 페이지 교체(Page Replacement)를 끊임없이 반복하게 되고, CPU는 실제 작업보다 페이지 교체 작업에 더 많은 시간을 소비하게 됩니다.

1.2 발생 원인

Thrashing은 다음과 같은 상황에서 발생합니다:

1) 과도한 다중 프로그래밍 (Multiprogramming Degree)

  • 너무 많은 프로세스가 동시에 메모리에 올라가면 각 프로세스가 필요한 페이지를 메모리에 유지하기 어려워집니다
  • 각 프로세스에 할당된 프레임(Frame)이 너무 적어 페이지 폴트가 빈번하게 발생합니다

2) 작업 집합(Working Set) 크기 초과

  • 전체 프로세스들의 작업 집합 크기 합계가 물리 메모리 크기를 초과할 때
  • 수식: (\sum WSS_i > \text{Total Physical Memory})

3) 악순환 고리

CPU 이용률 저하 
  → OS가 새 프로세스 추가 
  → 각 프로세스의 메모리 할당량 감소 
  → Page Fault 증가 
  → CPU 이용률 저하 (반복)

1.3 Thrashing의 증상

  • CPU 이용률 급격한 감소: 대부분의 시간을 I/O 대기에 소비
  • 디스크 I/O 활동 급증: 지속적인 Swap In/Out
  • 응답 시간 증가: 시스템 전체가 느려짐
  • 프로세스 처리량(Throughput) 감소: 실제 작업 처리 능력 저하

1.4 Thrashing 방지 방법

해결 방법 설명
메모리 할당 조정 멀티프로그래밍 정도를 조절하여 동시 실행 프로세스 수 제한
Working Set Model 프로세스가 실제로 사용하는 페이지만 메모리에 유지
PFF (Page Fault Frequency) 페이지 폴트 발생 빈도를 모니터링하여 메모리 할당 동적 조정
페이지 교체 알고리즘 개선 LRU, Clock 등 효율적인 알고리즘 적용
물리적 메모리 확장 RAM 용량 증설 (근본적 해결책)

2. Working Set Model (작업 집합 모델)

2.1 기본 개념

Working Set프로세스가 일정 시간 동안 원활하게 수행되기 위해 한꺼번에 메모리에 올라와 있어야 하는 페이지들의 집합입니다. 이는 Locality of Reference(참조 지역성) 원리에 기반합니다.

2.2 Locality of Reference (참조 지역성)

프로그램은 특정 시간 동안 일정 장소만을 집중적으로 참조하는 경향이 있습니다:

1) Temporal Locality (시간적 지역성)

  • 최근에 참조된 메모리 위치가 가까운 미래에 다시 참조될 가능성이 높음
  • 예: 반복문(Loop)에서 같은 명령어 반복 실행

2) Spatial Locality (공간적 지역성)

  • 참조된 메모리 위치 근처의 위치가 곧 참조될 가능성이 높음
  • 예: 배열 순회 시 연속된 메모리 접근

2.3 Working Set의 구성 요소

Working Set 관련 용어:

  1. Working Set (WS): 물리 메모리에 유지할 페이지들의 집합
  2. Working Set Window (Δ): 작업 집합을 선택하기 위한 탐색 범위 (시간 단위)
  3. Working Set Size (WSS): 작업 집합에 포함된 페이지의 개수

수식 표현:
[

W(t, Δ) = { 페이지 p | p는 (t - Δ, t] 구간 동안 접근됨 }]

2.4 Working Set 예시

현재 시점 t1에서 과거 10개 페이지 참조를 검사 (Δ = 10)
참조 순서: 1, 2, 5, 6, 7, 2, 1, 5, 6, 3

Working Set WS(t1) = {1, 2, 3, 5, 6, 7}  (중복 제거)
Working Set Size = 6

2.5 Working Set Model의 동작 원리

Thrashing 방지 메커니즘:

  1. 각 프로세스의 WSS 계산
    [
    D = \sum_{i=1}^{N} WSS_i
    ]
    여기서 (D)는 총 요구 프레임 수
  2. 메모리 할당 결정
    • (D > m) (총 가용 프레임 수): Thrashing 발생 위험
    • 해결: 일부 프로세스를 Swap Out (일시 중단)
  3. 멀티프로그래밍 정도 조절
    • WSS를 충족시킬 수 있는 만큼만 프로세스 허용

3. PFF (Page Fault Frequency)

3.1 PFF란?

Page Fault Frequency는 페이지 폴트 발생 빈도를 직접 모니터링하여 Thrashing을 방지하는 알고리즘입니다. Working Set Model보다 구현이 간단하고 오버헤드가 적습니다.

3.2 PFF의 동작 원리

상한선(Upper Threshold)과 하한선(Lower Threshold) 설정:

Page Fault Rate 상한선을 초과
  → 프로세스가 더 많은 메모리 필요
  → Frame 추가 할당

Page Fault Rate 하한선 미만
  → 프로세스가 메모리를 충분히 보유
  → Frame 회수

3.3 PFF 알고리즘 상세

1) Inter-Page-Fault-Time 기반 판단

  • (P = 1/T) (P: PFF 파라미터, T: 임계 시간)
  • 현재 페이지 폴트와 이전 페이지 폴트 사이 시간 측정

2) 증가 결정 (Increase Decision)

if (현재_시간 - 이전_페이지폴트_시간) ≤ T:
    메모리 할당 1 페이지 증가
    (페이지 교체 없이 추가)

3) 감소 결정 (Decrease Decision)

if (현재_시간 - 이전_페이지폴트_시간) > T:
    마지막 페이지 폴트 이후 참조되지 않은 페이지 해제

3.4 PFF vs Working Set

특성 PFF Working Set
계산 복잡도 낮음 높음 (주기적 계산 필요)
오버헤드 적음 상대적으로 많음
반응 속도 빠름 (페이지 폴트 시에만 동작) 주기적 업데이트
정확도 직접 측정 추정 기반
구현 난이도 쉬움 복잡함

4. Admission Control (승인 제어)

4.1 Admission Control이란?

Admission Control은 시스템이 새로운 프로세스를 메모리에 허용할지 여부를 결정하는 메커니즘입니다. Thrashing을 사전에 방지하기 위한 예방적 접근법입니다.

4.2 과거 OS의 접근 방식

전통적인 Admission Control:

1. 모든 프로세스의 Working Set 크기 계산
2. 총 WSS가 물리 메모리 용량 초과 여부 확인
3. 초과 시: 일부 프로세스 중단 (Suspend)
4. 메모리 여유 생기면: 중단된 프로세스 재개

장점:

  • 예측 가능한 성능 제공
  • Thrashing 사전 방지

단점:

  • 일부 프로세스가 완전히 중단됨
  • CPU 이용률이 최적화되지 않을 수 있음

4.3 현대적 접근: Linux의 방식

Linux는 전통적인 Admission Control 대신 메모리 오버커밋(Memory Overcommit) 정책과 OOM Killer를 사용합니다.

메모리 오버커밋:

  • 프로세스가 요청한 메모리를 실제 물리 메모리보다 많이 할당 가능
  • 대부분의 프로세스는 할당받은 메모리를 전부 사용하지 않는다는 가정
  • 장점: 메모리 활용률 극대화

5. Linux OOM Killer

5.1 OOM Killer란?

Out-of-Memory Killer는 Linux 커널이 메모리 부족 상황에서 시스템 안정성을 유지하기 위해 프로세스를 강제 종료하는 메커니즘입니다.

동작 시점:

  • 물리 메모리(RAM) 완전 소진
  • Swap 공간도 고갈
  • 커널의 메모리 회수 시도 실패

5.2 OOM Killer의 동작 과정

1단계: 트리거 조건 확인

물리 메모리 고갈 
  AND Swap 공간 고갈 
  AND 페이지 캐시 회수 실패
    → OOM Killer 활성화

2단계: OOM Score 계산

모든 프로세스에 대해 점수 계산:

// 기본 점수 계산
points = RSS + Swap + (PageTable / PAGE_SIZE)

// 조정값 적용
points += (oom_score_adj * totalpages / 1000)

// 최종 점수
oom_score = points

5.3 OOM Score 계산 요소

요소 영향 설명
메모리 사용량 증가(+) 물리 메모리 + 가상 메모리 사용량
프로세스 특권 감소(-) Root 권한 프로세스는 보호
CPU 시간 감소(-) 오래 실행된 프로세스 보호 (2.6.36 이전)
oom_score_adj 증가/감소(±) 사용자 정의 조정값 (-1000 ~ +1000)

5.4 oom_score와 oom_score_adj

1) oom_score (읽기 전용)

# 현재 프로세스의 OOM Score 확인
cat /proc/[PID]/oom_score

점수가 높을수록 종료될 가능성이 높습니다.

2) oom_score_adj (조정 가능)

# 프로세스를 OOM Killer로부터 보호
echo -1000 > /proc/[PID]/oom_score_adj  # 완전 보호

# 프로세스를 우선 종료 대상으로 지정
echo 1000 > /proc/[PID]/oom_score_adj   # 우선 종료

# 일반적인 조정 (50% 메모리 할당 우선권)
echo 500 > /proc/[PID]/oom_score_adj

oom_score_adj 값의 의미:

  • -1000: OOM Killer에서 완전히 제외 (절대 종료 안 됨)
  • -500: 약 50% 메모리 사용량 할인 (종료 가능성 감소)
  • 0: 기본값 (조정 없음)
  • +500: 약 50% 메모리 추가 계산 (종료 가능성 증가)
  • +1000: 최우선 종료 대상

5.5 OOM Killer 선택 알고리즘

Victim 선택 프로세스:

1. Threshold 결정
   - 메모리 압박 수준에 따른 기준 점수 설정

2. 후보 필터링
   - 시스템 중요 프로세스 제외
   - oom_score_adj = -1000 프로세스 제외
   - init (PID 1) 제외

3. Badness 계산
   for each process:
       badness = oom_badness(process)
       if badness > max_badness:
           victim = process

4. 선택 및 종료
   - 가장 높은 badness 프로세스에 SIGKILL 전송
   - 메모리 회수
   - 충분하지 않으면 반복

5.6 OOM Killer 로그 확인

# OOM Killer 동작 로그 확인
dmesg | grep -i "killed process"

# 또는
grep -i "Out of memory" /var/log/messages

로그 예시:

Out of memory: Killed process 12345 (java) 
total-vm:8120532kB, anon-rss:6891234kB, file-rss:0kB, 
shmem-rss:0kB, UID:1000 pgtables:16384kB oom_score_adj:0

5.7 OOM Killer 설정 조정

1) vm.overcommit_memory 설정

# 현재 설정 확인
cat /proc/sys/vm/overcommit_memory

# 설정 변경
echo 1 > /proc/sys/vm/overcommit_memory

값의 의미:

  • 0 (기본값): 휴리스틱 오버커밋 (적절히 판단)
  • 1: 항상 오버커밋 허용
  • 2: 오버커밋 엄격히 제한

2) vm.swappiness 설정

# Swap 사용 선호도 조정 (0-100)
echo 60 > /proc/sys/vm/swappiness
  • 0: Swap 최소화 (메모리 압박 시에만)
  • 60: 기본값 (균형)
  • 100: Swap 적극 사용

5.8 OOM Killer vs Thrashing 방지

접근 방식 Thrashing 방지 (과거) OOM Killer (현대)
철학 예방적 (Preventive) 대응적 (Reactive)
방법 Admission Control로 프로세스 제한 메모리 부족 시 프로세스 종료
장점 Thrashing 사전 방지 메모리 활용률 극대화
단점 CPU 유휴 시간 증가 가능 중요 프로세스 종료 위험
대상 과거 Unix 시스템 현대 Linux 시스템

6. 실전 예제: 프로세스 보호하기

6.1 중요 데이터베이스 프로세스 보호

#!/bin/bash

# PostgreSQL 프로세스 찾기
PID=$(pgrep postgres | head -1)

if [ -n "$PID" ]; then
    # OOM Killer로부터 보호
    echo -1000 > /proc/$PID/oom_score_adj
    echo "PostgreSQL (PID: $PID) protected from OOM Killer"
else
    echo "PostgreSQL process not found"
fi

6.2 메모리 집약적 배치 작업 우선 종료 설정

#!/bin/bash

# 배치 작업 실행 시
nice -n 19 ./batch_job &
BATCH_PID=$!

# OOM 발생 시 우선 종료 대상으로 설정
echo 800 > /proc/$BATCH_PID/oom_score_adj

echo "Batch job (PID: $BATCH_PID) set as OOM victim priority"

6.3 시스템 메모리 상태 모니터링

#!/bin/bash

# 메모리 사용률 모니터링
while true; do
    TOTAL=$(free | grep Mem | awk '{print $2}')
    USED=$(free | grep Mem | awk '{print $3}')
    PERCENT=$(echo "scale=2; $USED * 100 / $TOTAL" | bc)

    echo "[$(date)] Memory Usage: ${PERCENT}%"

    # 90% 이상 시 경고
    if (( $(echo "$PERCENT > 90" | bc -l) )); then
        echo "WARNING: High memory usage!"
        # 상위 10개 메모리 소비 프로세스 출력
        ps aux --sort=-%mem | head -11
    fi

    sleep 60
done

7. 정리 및 Best Practices

7.1 핵심 개념 정리

  1. Thrashing: 페이지 교체가 실제 작업보다 많아지는 현상
  2. Working Set: 프로세스가 필요로 하는 최소 페이지 집합
  3. PFF: 페이지 폴트 빈도로 메모리 할당 동적 조정
  4. Admission Control: 과거 방식의 예방적 프로세스 관리
  5. OOM Killer: 현대 Linux의 대응적 메모리 관리

7.2 Best Practices

1) 시스템 관리자 관점

  • 중요 프로세스는 oom_score_adj로 보호
  • 메모리 모니터링 자동화 구축
  • Swap 공간 적절히 설정 (RAM의 50-100%)
  • vm.swappiness 워크로드에 맞게 조정

2) 개발자 관점

  • 메모리 누수(Memory Leak) 방지
  • Locality of Reference 고려한 코드 작성
  • 대용량 데이터 처리 시 스트리밍 방식 사용
  • 메모리 할당 패턴 최적화

3) 시스템 설계 관점

  • 충분한 물리 메모리 확보 (근본적 해결책)
  • 메모리 집약적 작업 분산 처리
  • 컨테이너 환경에서 메모리 제한 설정
  • 모니터링 및 알림 시스템 구축

7.3 참고 명령어

# 메모리 상태 확인
free -h
vmstat 1

# OOM 관련 설정 확인
cat /proc/sys/vm/overcommit_memory
cat /proc/sys/vm/swappiness

# 프로세스별 메모리 사용량
ps aux --sort=-%mem | head -20

# OOM Killer 로그
dmesg | grep -i oom
journalctl -k | grep -i oom

# Swap 상태 확인
swapon --show
cat /proc/swaps

참고 자료

  • Linux Kernel Documentation: Memory Management
  • Operating Systems: Three Easy Pieces (OSTEP)
  • Understanding the Linux Virtual Memory Manager (Mel Gorman)
  • Red Hat Enterprise Linux Documentation
  • ACM: The Page Fault Frequency Replacement Algorithm (W.W. Chu, 1972)