물리 메모리 할당 관리

sungho·2024년 12월 3일
0

가상 메모리

목록 보기
5/11

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 작업에 적합한 메모리 할당 가능

할당 플래그

  • GFP_KERNEL
    • 일반적인 커널 메모리 할당, sleep 가능
  • GFP_ATOMIC
    • 인터럽트 컨텍스트에서 사용, sleep 불가

특징

  • 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
    • 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()로 진입

  1. 초기 단계
    • kswapd 데몬 깨우기 (GFP_RECLAIM_KSWAPD 플래그 설정 시)
    • WMARK_HIGH 기준으로 free pages 확인
    • shrink_node() 호출하여 모든 zone 정리
  2. 직접 회수 시도
    • __alloc_pages_direct_reclaim() 호출
    • try_to_free_pages()로 동기식 페이지 회수
    • I/O 작업 포함한 모든 타입의 페이지 회수
  3. 메모리 압축
    • __alloc_pages_direct_compact() 호출
    • order > 0인 경우 메모리 압축 시도
    • 실패 시 WMARK_NO 기준으로 재시도
  4. 최후의 수단
    • 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 개의 연속된 페이지로 구성
    • order 0
      • 2^0 = 1 페이지
    • order 4
      • 2^4 = 16 페이지
    • 최대 order
      • 2^(MAX_ORDER-1) 페이지

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
      • CPU별 프리 객체 배열
    • kmem_cache_node
      • 슬랩 페이지 관리
  • SLUB의 주요 구조체
    • kmem_cache
      • 단순화된 캐시 관리
    • kmem_cache_cpu
      • CPU별 프리리스트
    • struct page in slub
      • 페이지 단위 객체 관리

5. 메모리 디버깅 도구

KASAN(Kernel Address Sanitizer)

  • 동적 메모리 오류 감지기
  • use-after-free 및 범위 초과 접근 탐지
  • 대부분의 아키텍처에서 사용 가능

KFENCE(Kernel Electric Fence)

  • KASAN의 저부하 대안
  • x86, arm64, powerpc 아키텍처 지원
  • 성능과 정밀도의 균형 제공

Kmemleak

  • 동적 메모리 누수 검사기
  • 모든 아키텍처에서 사용 가능
  • 지속적인 메모리 누수 모니터링

0개의 댓글