🐧 Linux

Linux 메모리 컴팩션

개요

Linux 메모리 컴팩션(Memory Compaction)은 시스템 가동 중 물리 메모리 파편화(fragmentation)를 해결하여 연속된 큰 메모리 영역을 확보하는 메커니즘입니다. THP(Transparent Huge Pages), hugetlbfs, DMA 버퍼 할당 등에서 요구하는 고차(order) 연속 할당을 가능하게 합니다.

커널 문서에 따르면, 시스템이 실행되면서 태스크들은 메모리를 할당하고 해제하고, 이 과정에서 파편화가 발생합니다. 가상 메모리를 통해 흩어진 물리 페이지를 가상 연속 범위로 제시할 수 있지만, 때로는 크고 물리적으로 연속된 영역이 필요합니다. 컴팩션은 메모리 존(zone)의 하부에서 사용 중인 페이지를 상부의 빈 페이지로 이동시켜, 빈 페이지들이 존의 처음 부분으로 모이도록 합니다.

Linux 메모리 컴팩션 개요

그림 1. Linux 메모리 컴팩션의 위치 - buddy allocator, THP, kswapd와의 관계

핵심 개념

파편화(Fragmentation) 문제

물리 메모리 파편화는 시스템이 오래 실행될수록 심해집니다. 가상 메모리는 흩어진 물리 페이지를 연속된 것처럼 보이게 만들 수 있지만, THP 할당(2MB), DMA 버퍼 할당 같은 경우 실제 물리적으로 연속된 메모리가 필요합니다.

  • 외부 파편화(External Fragmentation): 총 여유 메모리는 충분하지만 연속된 큰 블록을 확보할 수 없는 상태
  • 내부 파편화(Internal Fragmentation)**: 할당된 블록 내부에 사용되지 않는 공간이 있는 상태
  • compaction은 주로 외부 파편화를 해결합니다

Buddy Allocator와 고차 할당

Linux의 물리 메모리 할당자는 buddy allocator입니다. 이 할당자는 2의 거듭제곱 크기 블록(order 0~N)을 관리합니다.

Order 크기 (4KB 기준) 설명
0 4KB 기본 페이지
1 8KB 2페이지
2 16KB 4페이지
... ... ...
8 2MB THP 크기
9 4MB 2MB × 2
10 1GB 1GB huge page

buddy allocator는 같은 order의 빈 블록 2개가 연속되면 상위 order로 병합합니다. 하지만 파편화가 심해지면 특정 order의 빈 블록을 확보할 수 없게 됩니다. 이때 compaction이 동작합니다.

Page Block과 Migration Type

커널은 물리 메모리를 page block 단위로 분류하고, 각 page block에 migration type을 지정합니다:

  • MOVABLE: 이동 가능한 페이지 (사용자 공간 페이지, page cache 등)
  • UNMOVABLE: 이동 불가능한 페이지 (커널 내부 구조체, DMA 버퍼 등)
  • RECLAIMABLE: 재생 가능한 페이지 (SLAB 캐시 등)
  • CMA: Contiguous Memory Allocator 영역
  • ISOLATE: 리소스 격리된 페이지

migration type은 페이지 할당 시 해당 유형의 페이지들이 같은 page block에 모이도록 하여, compaction 효율을 높입니다. __GFP_MOVABLE 플래그는 페이지가 compaction 중 이동될 수 있음을 나타냅니다.

Compaction 동작 원리

Scanner-Migrate 모델

compaction의 핵심은 두 개의 스캐너가 존의 양쪽 끝에서 시작하여 중간 어딘가에서 만나는 모델입니다:

Compaction Scanner-Migrate 모델

그림 2. compaction의 두 스캐너 동작 원리

1. Migrate Scanner (존 하부에서 시작)
- 존의 하부부터 상부로 이동하며 이동 가능한 페이지를 탐색
- 이동 가능한 페이지를 isolation 목록에 추가
- 페이지 테이블 항목을 migration entry로 변환하여 해당 페이지에 대한 접근을 차단

2. Free Scanner (존 상부에서 시작)
- 존의 상부부터 하부로 이동하며 빈 페이지를 탐색
- 빈 페이지를 free page 목록에 추가
- 이 빈 페이지들은 migrate scanner가 찾은 페이지의 이동 대상이 됨

3. Page Migration
- 두 스캐너가 만나면, isolate된 페이지를 빈 페이지 위치로 실제로 이동
- 페이지 내용 복사, 페이지 테이블 업데이트, LRU 목록 갱신 수행

상세 동작 흐름

Compaction 흐름:
  1. Migrate Scanner가 존 하부를 스캔 → 이동 가능한 페이지 탐색
  2. Free Scanner가 존 상부를 스캔 → 빈 페이지 탐색
  3. 두 스캐너가 중간에서 만남
  4. Page Migration 수행:
     a. 소스 페이지에 page lock 획득
     b. writeback 완료 확인
     c. 대상 빈 페이지 lock
     d. 페이지 테이블 항목을 migration entry로 변환
     e. radix tree(i_pages) lock
     f. refcount 확인 → 유일한 참조인지 확인
     g. 새 페이지에 설정 복사
     h. radix tree 갱신
     i. 페이지 내용 복사
     j. page flags 복사
     k. migration entry를 실제 PTE로 교체
     l. lock 해제 → 대기 중인 프로세스가 새 페이지에 접근
     m. 새 페이지를 LRU에 추가
  5. 연속된 빈 페이지 영역 확보

페이지 이동 가능성

모든 페이지를 이동할 수 있는 것은 아닙니다:

  • 이동 가능한 페이지: 사용자 공간 페이지(페이지 테이블을 통해 접근), page cache의 clean page 등. 페이지 테이블 항목만 업데이트하면 됩니다.
  • 이동 불가능한 페이지: 커널이 직접 사용하는 메모리, DMA 버퍼, mlocked 페이지 등. 하나의 이동 불가능한 페이지도 연속 블록을 방해할 수 있습니다.
  • 재생 가능한 페이지: 이동할 수 없지만, 재생(reclaim)을 통해 완전히 해제될 수 있습니다. compaction 시 이동 대신 재생을 수행할 수도 있습니다.

커널은 이미 이동 가능/불가능한 페이지를 같은 page block에 분리하여 배치하므로, 실제로는 이동 불가능한 페이지가 큰 문제가 되지 않습니다.

Compaction 유형

1. Direct Compaction (직접 컴팩션)

메모리 할당 요청이 실패했을 때, 할당을 요청한 프로세스가 직접 compaction을 수행합니다.

  • 발동 조건: 고차(order) 할당이 실패했을 때, direct reclaim 대신 compaction을 먼저 시도
  • 특징: 할당 요청을 처리하는 프로세스가 동기적으로 대기
  • 영향: 프로세스 지연 시간 증가 (compact_stall 카운터로 모니터링)
  • 사용 예: THP 할당 실패 시, DMA 버퍼 할당 실패 시
// mm/page_alloc.c의 __alloc_pages() 경로에서 호출
// GFP_TRANSHUGE 또는 고차 할당 실패 시
compact_zone_order() → try_to_compact_pages()

2. kcompactd (백그라운드 컴팩션)

NUMA 노드별로 동작하는 백그라운드 커널 스레드입니다.

  • 발동 조건: watermarks를 충족하기 위해 또는 특정 조건에서 자동으로 동작
  • 특징: 비동기적으로 동작하여 할당 요청에 직접 영향을 주지 않음
  • 목적: 미리 연속된 빈 페이지 영역을 확보해두어 할당 실패 가능성을 줄임
  • 동작: 특정 존에서 compaction을 수행하여 연속 블록 확보

3. Proactive Compaction (사전 컴팩션)

커널이 파편화 수준을 모니터링하고, 미리 compaction을 수행하는 메커니즘입니다.

  • 발동 조건: vm.compaction_proactiveness 파라미터가 0이 아닌 경우
  • 동작 주기: 주기적으로 파편화 수준을 확인하고 필요 시 compaction 수행
  • 특징: 시스템 부하가 낮을 때 미리 compaction을 수행하여 고부하 시 할당 지연을 예방
  • 파라미터: vm.compaction_proactiveness (0~100, 기본값 20)

4. Manual Compaction

관리자가 /proc/sys/vm/compact_memory에 1을 써서 수동으로 모든 존의 compaction을 트리거할 수 있습니다.

  • 용도: huge page 할당 전 사전 준비, 시스템 유지보수
  • 명령: echo 1 > /proc/sys/vm/compact_memory

Compaction 관련 튜너블

핵심 튜너블 파라미터

파라미터 경로 기본값 설명
compact_memory /proc/sys/vm/ - 쓰기 시 모든 존 compaction 수행
compaction_proactiveness /proc/sys/vm/ 20 사전 compaction 공격성 (0~100)
compact_unevictable_allowed /proc/sys/vm/ 1 unevictable LRU의 페이지 compaction 허용 여부
extfrag_threshold /proc/sys/vm/ 500 compaction 대신 direct reclaim를 선택하는 파편화 임계값
watermark_boost_factor /proc/sys/vm/ 15000 파편화 시 kswapd 회수 수준 (high watermark의 %)
watermark_scale_factor /proc/sys/vm/ 10 kswapd 동작 watermarks 간격 (10,000분율)

compaction_proactiveness 상세

  • 0: 사전 compaction 비활성화
  • 1~20: 보수적 동작 (기본값 20)
  • 21~80: 일반 동작
  • 81~100: 공격적 동작 (파편화 증가에 더 민감하게 반응, 잦은 compaction 발생)

extfrag_threshold 상세

파편화 인덱스(fragmentation index)가 이 값 이하면 compaction 대신 direct reclaim를 수행합니다:
- 값이 0에 가까움: 메모리 부족으로 인한 할당 실패
- 값이 1000에 가까움: 파편화로 인한 할당 실패
- 값이 -1: watermarks가 충족되면 할당 성공

defrag_mode (최신 커널)

/proc/sys/vm/defrag_mode가 1이면, 페이지 할당자가 파편화를 줄이고 고차 할당 가능성을 유지하려고 더 노력합니다. 부팅 직후 활성화하면 파편화가 영구적으로 남는 것을 방지할 수 있습니다.

THP defrag 정책과의 관계

/sys/kernel/mm/transparent_hugepage/defrag 설정은 THP 할당 시 compaction 동작을 제어합니다:

정책 동작
always THP 할당 실패 시 즉시 직접 compaction 수행
defer kswapd와 kcompactd를 백그라운드에서 깨움
defer+madvise MADV_HUGEPAGE 영역에서 always, 나머지는 defer
madvise MADV_HUGEPAGE 영역에서만 직접 compaction (기본값)
never THP를 위해 compaction을 수행하지 않음

관련 커널 메커니즘

Reclaim과의 관계

compaction은 reclaim과 밀접하게 관련되어 있습니다:

  1. Reclaim (회수): 사용되지 않는 페이지를 해제하여 메모리 확보
  2. Compaction (압축): 해제된 페이지를 연속되도록 재배치
  3. 협력: compaction 과정에서 이동할 수 없는 페이지는 재생 가능한 페이지인 경우, 이동 대신 재생을 수행할 수 있습니다

메모리 압박 시 순서:
1. watermarks 도달 → kswapd가 비동기 회수 시작
2. watermarks 미달 → 직접 회수(direct reclaim) 발생
3. 고차 할당 실패 → compaction 시도
4. compaction 실패 → OOM killer 발동

CMA (Contiguous Memory Allocator)

CMA는 장치 드라이버를 위해 미리 확보된 연속 메모리 영역입니다:

  • 부팅 시 cma= 파라미터로 크기를 지정
  • 평시에는 일반 할당에 사용 가능
  • 장치가 DMA 버퍼를 요청하면 compaction을 통해 CMA 영역을 확보
  • compaction과 함께 동작하여 연속 메모리 보장

ZONE_MOVABLE

ZONE_MOVABLE은 compaction 효율을 높이기 위해 도입된 가상 존입니다:

  • 이동 가능한 페이지만 배치
  • 메모리 핫플러그 지원
  • compaction이 쉬운 영역 분리
  • HugeTLB gigantic 페이지 할당에 활용 가능 (vm.movable_gigantic_pages)

모니터링 및 디버깅

/proc/vmstat 카운터

카운터 설명
compact_stall 직접 compaction으로 인한 할당 지연 횟수
compact_success compaction 성공 횟수
compact_fail compaction 실패 횟수
compact_pages_moved compaction으로 이동된 페이지 수
compact_pagemigrate_free compaction으로 해제된 페이지 수
compact_stall_millisecs compaction으로 인한 총 지연 시간 (ms)
compact_flow_stall compaction 흐름 차단 횟수
compact_num_migrate_scanned migrate scanner가 스캔한 페이지 수
compact_num_free_scanned free scanner가 스캔한 페이지 수
compact_num_isolated_pgpg 격리된 페이지 수 (THP)

/proc/meminfo

  • CompactStall: compaction으로 인한 stall 시간 (ms)
  • HugePages_Total: huge page 총 수 (compaction으로 확보된 huge page 포함)

/proc//smaps

  • Compact: 해당 프로세스의 compact 관련 통계

debugfs

  • /sys/kernel/debug/extfrag/index: 존별 파편화 인덱스
  • /sys/kernel/debug/cma/: CMA 영역 정보

성능 영향과 튜닝 포인트

Compaction의 성능 비용

  1. CPU 오버헤드: 페이지 이동을 위한 스캐닝과 복사
  2. 지연 시간: 직접 compaction은 할당 요청자를 대기시킴
  3. 버스 타임: lock 획득/해제, TLB 플러시
  4. 캐시 영향: 이동된 페이지의 캐시 라인 콜드

튜닝 가이드

1. 파편화 예방
- 시스템 부팅 직후 vm.defrag_mode=1 설정으로 초기 파편화 방지
- 불필요한 고차 할당을 줄여 파편화 유발 요소 제거

2. 사전 compaction 활성화
- vm.compaction_proactiveness=20~50: 적절한 백그라운드 compaction
- 메모리 압박이 예상되는 시스템에서는 값 높이기

3. THP defrag 정책 선택
- 지연 시간 민감: madvise 또는 never
- THP 성능 중요: always 또는 defer
- 균형: defer+madvise

4. watermark 튜닝
- vm.watermark_scale_factor 증가: kswapd가 더 일찍 동작
- vm.watermark_boost_factor 조정: 파편화 시 회수 수준 제어

5. extfrag_threshold 조정
- 값 높이기: compaction을 더 자주 사용
- 값 낮추기: direct reclaim를 더 선호

모니터링 포인트

  • compact_stall이 지속적으로 증가하면 직접 compaction이 빈번하다는 신호
  • compact_success 대비 compact_fail 비율이 높으면 파편화가 심하다는 신호
  • compact_pagemigrate_free 대비 compact_pages_moved 비율이 낮으면 이동 불가능한 페이지가 많다는 신호

최신 커널의 Compaction 개선 사항

Linux 5.x~6.x 주요 개선

  1. Proactive Compaction 강화
    - 더 효율적인 파편화 감지 알고리즘
    - 불필요한 compaction 동작 최소화
    - 파편화 수준 변화에 대한 민감도 조정

  2. mTHP(multi-size THP) 지원
    - 16KB, 32KB, 64KB 같은 중간 크기 THP 지원
    - compaction 없이도 부분적인 TLB 효율 확보 가능
    - 지연 시간 급증 최소화

  3. Folio 기반 처리
    - 개별 페이지 대신 folio 단위로 compaction 수행
    - THP 처리 효율 향상
    - 메모리 관리 코드 단순화

  4. compaction_heuristics 개선
    - 파편화 인덱스 계산 개선
    - 존별 특성에 맞는 compaction 결정
    - 불필요한 compaction 회피

  5. CMA 개선
    - 더 효율적인 CMA 영역 관리
    - CMA와 compaction의 통합 동작 개선
    - 메모리 핫플러그와의 원활한 연동

  6. NUMA 인식 compaction 강화
    - NUMA topology을 고려한 compaction 결정
    - 원격 메모리 이동 최소화
    - 노드 간 compaction 부하 분산

  7. Compaction 비용 추정 개선
    - 실제 compaction 수행 전 비용 추정
    - 비용 대비 이익이 낮으면 compaction 회피
    - 시스템 부하에 적응적 동작

비교/분석

메커니즘 목적 동작 시점 비용 효과
Reclaim 메모리 회수 watermarks 미달 I/O, CPU 빈 페이지 확보
Compaction 파편화 해결 고차 할당 실패/사전 CPU, 지연 연속 블록 확보
Direct Reclaim 메모리 회수 할당 요청 시 높음 (동기) 즉시 빈 페이지
kswapd 메모리 회수 watermarks 도달 낮음 (비동기) 백그라운드 회수
Proactive Compaction 파편화 예방 주기적 중간 사전 준비
CMA 연속 메모리 확보 DMA 할당 시 중간 보장된 연속 영역

동작 원리 요약

  1. 시스템 가동 중 메모리 할당/해제가 반복되면서 파편화 발생
  2. THP, DMA 버퍼 같은 고차 할당이 실패하면 compaction 트리거
  3. migrate scanner가 이동 가능한 페이지를, free scanner가 빈 페이지를 탐색
  4. 두 스캐너가 만나면 page migration를 통해 페이지를 재배치
  5. 연속된 빈 페이지 영역이 확보되면 고차 할당 성공
  6. 사전 compaction은 미리 파편화를 줄여 할당 실패를 예방

장단점

장점

  • 파편화 해소: 물리 메모리 파편화를 해결하여 THP, DMA 버퍼 등 고차 연속 할당을 가능하게 함
  • 시스템 안정성 확보: 파편화로 인한 할당 실패를 예방하여 시스템이 장기간 안정적으로 동작하도록 지원
  • 유연한 동작 모드: 직접 컴팩션, 백그라운드(kcompactd), 사전 컴팩션 등 다양한 동작 모드로 상황에 맞는 대응 가능
  • 운영 편의성: /proc/sys/vm/ 파라미터로 동작을 세밀하게 튜닝할 수 있음
  • NUMA 인식: NUMA 토폴로지를 고려하여 원격 메모리 이동을 최소화하고 노드 간 부하를 분산

단점

  • CPU 오버헤드: 페이지 스캐닝, 복사, 페이지 테이블 업데이트에 상당한 CPU 자원 소모
  • 직접 컴팩션 지연: 할당 요청 프로세스가 동기적으로 대기하여 응답 시간이 증가할 수 있음
  • 캐시 영향: 이동된 페이지의 캐시 라인이 콜드되어 성능 저하 가능
  • 이동 불가능한 페이지 제약: 커널 내부 구조체, DMA 버퍼 등 이동 불가 페이지가 있으면 효율이 저하
  • lock contention: 페이지 이동 과정에서 다수의 lock을 획득/해제하므로 동시성 병목 가능

핵심 정리

Linux 메모리 컴팩션은 시스템 가동 중 발생하는 물리 메모리 파편화를 해결하는 핵심 메커니즘이다. buddy allocator의 고차(order) 연속 할당 실패 시, migrate scanner와 free scanner가 존의 양쪽 끝에서 시작하여 중간에서 만나는 방식으로 페이지를 재배치한다. 직접 컴팩션, kcompactd 백그라운드 컴팩션, 사전(proactive) 컴팩션 등 다양한 동작 모드를 제공하며, compaction_proactiveness, extfrag_threshold, THP defrag 정책 등의 튜너블을 통해 운영 상황에 맞게 조정할 수 있다. THP, DMA 버퍼, CMA 등 다양한 고차 할당 수요를 지원하며, NUMA 인식 compaction을 통해 멀티소켓 시스템에서도 효율적으로 동작한다.

관련 기술

참고 자료