1. 메모리 할당 및 회수

Page Allocator
- 물리 메모리를 4096 bytes 단위의 페이지로 관리
- Binary Buddy Allocator를 통한 효율적인 메모리 블록 관리
- 할당 함수
- alloc_pages(), get_zeroed_page()
메모리 할당 방식
할당 방식 | 특징 | 주요 용도 |
---|
vmalloc | 가상 연속 메모리 | 대용량 할당, 커널 모듈 |
kmalloc | 물리 연속 메모리 | DMA 작업, 소형 객체 |
구성요소
Page Allocator
기본 구조
- 물리 메모리를 페이지 단위로 관리하며, 보통 x86 시스템에서는 4096 bytes가 기본 페이지 크기
- Binary Buddy Allocator 알고리즘을 사용하여 메모리 블록을 관리
함수
- alloc_pages(): 2^order 개수만큼의 페이지를 할당
- alloc_page(): 단일 페이지 할당을 위한 함수
- __get_free_pages(): 연속된 물리 페이지를 할당
- get_zeroed_page(): 초기화된 단일 페이지 할당
가상 연속 메모리
vmalloc 특징
- 물리적으로 불연속적인 메모리를 가상 주소 공간에서 연속적으로 매핑
- VMALLOC_START와 VMALLOC_END 사이의 영역을 사용
- x86에서는 최소 128MiB의 VMALLOC_RESERVE 크기 보장
기능
- 대용량 메모리 할당에 적합
- 물리적 연속성이 필요없는 커널 모듈 로딩에 사용
- 메모리 단편화 상황에서도 할당 가능
물리 연속 메모리
kmalloc 특징
- 물리적으로 연속된 메모리 공간 할당
- 작은 크기의 객체 할당에 최적화
- DMA 작업에 적합한 메모리 할당 가능
할당 플래그
특징
- vmalloc보다 빠른 접근 속도
- 물리 메모리와 1:1 매핑으로 인한 효율적인 메모리 접근
메모리 회수 매커니즘
직접 회수(Direct reclaim)
- alloc_pages()에서 try_to_free_pages() 호출
비동기 회수(Async reclaim)
- kswapd 프로세스를 통한 메모리 회수
- alloc_pages() → wakeup_kswapd() → balance_pgdat() 순서로 동작

구성요소
워터마크 레벨
- WMARK_HIGH
- WMARK_LOW
- WMARK_MIN
프로세스
페이지 소비 단계
- 시간이 지남에 따라 free_pages가 감소
- kswapd에 의해 페이지 소비 속도가 조절됨
회수 프로세스
- WMARK_LOW 이하로 떨어지면 kswapd가 깨어남
- 매핑되지 않은 캐시를 정리
- 실패 시 kswapd가 활성화됨
할당 프로세스
- 프로세스들이 동기적으로 페이지를 해제
- GFP_ATOMIC, RT 태스크, IRQ 등이 관여
- PF_MEMALLOC, TIF_MEMDIE 태스크 처리
밸런싱 단계
- Zone이 균형을 이루면 kswapd는 휴면 상태로 전환
- free_pages가 다시 증가하여 WMARK_HIGH까지 회복
2. 존 관리 시스템
Zone Allocator
물리 메모리를 '존(zone)'이라 불리는 영역으로 나눕니다. 메모리 관리의 효율성을 높이기 위함입니다
존 타입
- ZONE_DMA
- ZONE_NORMAL
- ZONE_HIGHMEM
Zone Watermarks
존 워터마크는 해당 존의 메모리 할당 상태를 나타냅니다. 워터마크가 높을수록 해당 존에 많은 메모리가 할당되었음을 의미합니다
워터마크 레벨
- WMARK_MIN
- WMARK_LOW
- WMARK_HIGH
3. Buddy System
버디 시스템은 rmqueue() 함수를 중심으로 동작합니다.
Fast Path

- 입력 파라미터 처리
- gfp, order, preferred_nid, nodemask를 입력받음
- prepare_alloc_pages() 호출하여 초기 설정
- highest_zoneidx, zonelist, alloc_flags 설정
- get_page_from_freelist() 실행
- 높은 zone부터 순차적으로 스캔
- WMARK_LOW 워터마크 이하면 node_reclaim() 호출
- rmqueue()로 페이지 할당 시도
- 성공하면 해당 페이지 반환

Slow Path
페이지 할당 실패 시 __alloc_pages_slowpath()로 진입
- 초기 단계
- kswapd 데몬 깨우기 (GFP_RECLAIM_KSWAPD 플래그 설정 시)
- WMARK_HIGH 기준으로 free pages 확인
- shrink_node() 호출하여 모든 zone 정리
- 직접 회수 시도
- __alloc_pages_direct_reclaim() 호출
- try_to_free_pages()로 동기식 페이지 회수
- I/O 작업 포함한 모든 타입의 페이지 회수
- 메모리 압축
- __alloc_pages_direct_compact() 호출
- order > 0인 경우 메모리 압축 시도
- 실패 시 WMARK_NO 기준으로 재시도
- 최후의 수단
- should_reclaim_retry()와 should_compact_retry() 조건 확인
- GFP 플래그가 허용하지 않으면 OOM 킬러 호출
- out_of_memory() 함수로 프로세스 종료
- order >= pcp_allowed_order() 조건에서 동작
- __rmqueue()를 호출하여 버디 시스템의 per-order, per-migrate_type 리스트에서 직접 할당
- 필요한 경우 expand() 함수로 큰 블록을 분할
- 남은 연속 페이지들은 하위 order 리스트에 삽입

Buddy System(struct free_area)
- 왼쪽의
struct free_area
는 버디 시스템을 구현한 자료구조
- 0부터 MAX_ORDER-1까지의 순서로 정렬된 빈 페이지 블록들을 관리
- 순서(order)는 2^n 개의 연속된 페이지로 구성
Per-CPU 페이지 캐시(struct per_cpu_pages)
- 오른쪽의
struct per_cpu_pages
는 CPU별 페이지 캐시를 나타냄
- CPU는 자신만의 페이지 리스트를 가지고 있어 동시성 문제를 감소
- 0-3까지의 인덱스로 구분된 페이지 리스트를 관리
- CPU 간의 락(lock) 경합을 줄여 성능을 향상시키는 구조
4. 슬랩 할당자
SLAB 구현
- kmem_cache 구조체로 객체별 캐시 관리
- array_cache를 통한 CPU별 캐시 구현
- struct page in slab으로 페이지 관리
- freelist를 통한 객체 할당/해제
- 복잡한 데이터 구조로 인한 오버헤드 존재
SLUB 구현
- 단순화된 구조로 성능 최적화
- kmem_cache_cpu로 CPU별 캐시 관리
- struct page in slub으로 페이지 단위 관리
- 페이지 기반 할당으로 메모리 효율성 증가
- CPU별 캐시와 partial 리스트로 캐시 히트율 향상
자료 구조
- SLAB의 주요 구조체
- kmem_cache
- array_cache
- kmem_cache_node
- SLUB의 주요 구조체
- kmem_cache
- kmem_cache_cpu
- struct page in slub
5. 메모리 디버깅 도구
KASAN(Kernel Address Sanitizer)
- 동적 메모리 오류 감지기
- use-after-free 및 범위 초과 접근 탐지
- 대부분의 아키텍처에서 사용 가능
KFENCE(Kernel Electric Fence)
- KASAN의 저부하 대안
- x86, arm64, powerpc 아키텍처 지원
- 성능과 정밀도의 균형 제공
Kmemleak
- 동적 메모리 누수 검사기
- 모든 아키텍처에서 사용 가능
- 지속적인 메모리 누수 모니터링