Linux 메모리 컴팩션
개요
Linux 메모리 컴팩션(Memory Compaction)은 시스템 가동 중 물리 메모리 파편화(fragmentation)를 해결하여 연속된 큰 메모리 영역을 확보하는 메커니즘입니다. THP(Transparent Huge Pages), hugetlbfs, DMA 버퍼 할당 등에서 요구하는 고차(order) 연속 할당을 가능하게 합니다.
커널 문서에 따르면, 시스템이 실행되면서 태스크들은 메모리를 할당하고 해제하고, 이 과정에서 파편화가 발생합니다. 가상 메모리를 통해 흩어진 물리 페이지를 가상 연속 범위로 제시할 수 있지만, 때로는 크고 물리적으로 연속된 영역이 필요합니다. 컴팩션은 메모리 존(zone)의 하부에서 사용 중인 페이지를 상부의 빈 페이지로 이동시켜, 빈 페이지들이 존의 처음 부분으로 모이도록 합니다.
그림 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의 핵심은 두 개의 스캐너가 존의 양쪽 끝에서 시작하여 중간 어딘가에서 만나는 모델입니다:
그림 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과 밀접하게 관련되어 있습니다:
- Reclaim (회수): 사용되지 않는 페이지를 해제하여 메모리 확보
- Compaction (압축): 해제된 페이지를 연속되도록 재배치
- 협력: 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의 성능 비용
- CPU 오버헤드: 페이지 이동을 위한 스캐닝과 복사
- 지연 시간: 직접 compaction은 할당 요청자를 대기시킴
- 버스 타임: lock 획득/해제, TLB 플러시
- 캐시 영향: 이동된 페이지의 캐시 라인 콜드
튜닝 가이드
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 주요 개선
-
Proactive Compaction 강화
- 더 효율적인 파편화 감지 알고리즘
- 불필요한 compaction 동작 최소화
- 파편화 수준 변화에 대한 민감도 조정 -
mTHP(multi-size THP) 지원
- 16KB, 32KB, 64KB 같은 중간 크기 THP 지원
- compaction 없이도 부분적인 TLB 효율 확보 가능
- 지연 시간 급증 최소화 -
Folio 기반 처리
- 개별 페이지 대신 folio 단위로 compaction 수행
- THP 처리 효율 향상
- 메모리 관리 코드 단순화 -
compaction_heuristics 개선
- 파편화 인덱스 계산 개선
- 존별 특성에 맞는 compaction 결정
- 불필요한 compaction 회피 -
CMA 개선
- 더 효율적인 CMA 영역 관리
- CMA와 compaction의 통합 동작 개선
- 메모리 핫플러그와의 원활한 연동 -
NUMA 인식 compaction 강화
- NUMA topology을 고려한 compaction 결정
- 원격 메모리 이동 최소화
- 노드 간 compaction 부하 분산 -
Compaction 비용 추정 개선
- 실제 compaction 수행 전 비용 추정
- 비용 대비 이익이 낮으면 compaction 회피
- 시스템 부하에 적응적 동작
비교/분석
| 메커니즘 | 목적 | 동작 시점 | 비용 | 효과 |
|---|---|---|---|---|
| Reclaim | 메모리 회수 | watermarks 미달 | I/O, CPU | 빈 페이지 확보 |
| Compaction | 파편화 해결 | 고차 할당 실패/사전 | CPU, 지연 | 연속 블록 확보 |
| Direct Reclaim | 메모리 회수 | 할당 요청 시 | 높음 (동기) | 즉시 빈 페이지 |
| kswapd | 메모리 회수 | watermarks 도달 | 낮음 (비동기) | 백그라운드 회수 |
| Proactive Compaction | 파편화 예방 | 주기적 | 중간 | 사전 준비 |
| CMA | 연속 메모리 확보 | DMA 할당 시 | 중간 | 보장된 연속 영역 |
동작 원리 요약
- 시스템 가동 중 메모리 할당/해제가 반복되면서 파편화 발생
- THP, DMA 버퍼 같은 고차 할당이 실패하면 compaction 트리거
- migrate scanner가 이동 가능한 페이지를, free scanner가 빈 페이지를 탐색
- 두 스캐너가 만나면 page migration를 통해 페이지를 재배치
- 연속된 빈 페이지 영역이 확보되면 고차 할당 성공
- 사전 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을 통해 멀티소켓 시스템에서도 효율적으로 동작한다.
관련 기술
- Linux 메모리 관리 기초 - 메모리 관리 전체 구조 이해
- 투명 거대 페이지 - THP가 compaction의 주요 사용자
- 스왑/zRAM - reclaim과의 관계
- cgroup 메모리 - 메모리 제한과 compaction 동작
- OOM 관리 - compaction 실패 후 최후 수단