linux2025. 12. 28. 16:20

 

 

Q.free_area는 4K의 승수별로 존재, list_head는 type 별 리스트를 가진다고 이해하면 되나

 

정확합니다! 당신의 이해가 맞습니다.

정리

free_area[order]의 구조:

free_area[0]  (2^0 = 1 page = 4KB)
├─ free_list[MIGRATE_UNMOVABLE]  → [page] → [page] → ...
├─ free_list[MIGRATE_MOVABLE]    → [page] → [page] → ...
├─ free_list[MIGRATE_RECLAIMABLE]→ [page] → [page] → ...
├─ free_list[MIGRATE_HIGHATOMIC] → [page] → ...
└─ free_list[MIGRATE_CMA]        → [page] → ...

free_area[1]  (2^1 = 2 pages = 8KB)
├─ free_list[MIGRATE_UNMOVABLE]  → [page] → [page] → ...
├─ free_list[MIGRATE_MOVABLE]    → [page] → [page] → ...
├─ free_list[MIGRATE_RECLAIMABLE]→ ...
├─ free_list[MIGRATE_HIGHATOMIC] → ...
└─ free_list[MIGRATE_CMA]        → ...

free_area[2]  (2^2 = 4 pages = 16KB)
├─ free_list[...]
└─ ...

...

free_area[10] (2^10 = 1024 pages = 4MB)
├─ free_list[...]
└─ ...

코드로 보면

struct zone {
    struct free_area free_area[MAX_ORDER];  // MAX_ORDER = 11
};

struct free_area {
    struct list_head free_list[MIGRATE_TYPES];  // MIGRATE_TYPES = 5
    unsigned long nr_free;
};

예시: 8KB 메모리 블록 찾기

// 8KB (2 pages) 크기의 MOVABLE 타입 메모리를 찾고 싶다면
struct list_head *target = &zone->free_area[1].free_list[MIGRATE_MOVABLE];
//                                          ↑                        ↑
//                                     order=1 (8KB)        type별 리스트
//                                    (2^1 page blocks)

할당/해제 관점

 
// 8KB 할당 요청이 오면
// → order=1, migratetype=MIGRATE_MOVABLE인 경우
// → zone->free_area[1].free_list[MIGRATE_MOVABLE]에서 페이지 블록 추출

// 8KB 메모리 해제
// → order=1, migratetype=MIGRATE_MOVABLE
// → zone->free_area[1].free_list[MIGRATE_MOVABLE]에 페이지 블록 추가
```

## 마이그레이션 타입 분리의 이점
```
같은 크기(order)여도 타입별로 분리:

free_area[1].free_list[MIGRATE_MOVABLE]    → 이동 가능한 8KB 블록들
free_area[1].free_list[MIGRATE_UNMOVABLE] → 이동 불가능한 8KB 블록들

→ 커널이 8KB 메모리를 할당할 때 UNMOVABLE 영역에서만 찾기
→ MOVABLE 영역을 보존 (메모리 압축/조각화 방지)

당신의 이해가 정확합니다!

  • ✅ 크기: 4KB의 승수별로 존재 (2^0, 2^1, ... 2^10)
  • ✅ 리스트: 각 크기별로 타입에 따른 5개의 리스트 보유
 
 
 
 
 

Q. 여기서 MIGRATE_TYPES는 zone의 종류와는다른거야?

 

네, 완전히 다른 개념입니다!

구분

MIGRATE_TYPES = 페이지의 이동 가능성 속성

#define MIGRATE_UNMOVABLE       0  // 커널이 사용, 이동 불가
#define MIGRATE_MOVABLE         1  // 사용자 프로세스, 이동 가능
#define MIGRATE_RECLAIMABLE     2  // 캐시, 회수 가능
#define MIGRATE_HIGHATOMIC      3  // 원자적 할당 예약
#define MIGRATE_CMA             4  // Contiguous Memory Allocator

Zone = 메모리의 물리적 위치 기준

enum zone_type {
    ZONE_DMA,        // 0-16MB (DMA 가능)
    ZONE_DMA32,      // 0-4GB (32bit DMA)
    ZONE_NORMAL,     // 일반 메모리
    ZONE_HIGHMEM,    // 고위 메모리 (32bit)
    ZONE_MOVABLE,    // 이동 가능 영역
    // ...
};

struct zone {
    struct free_area free_area[MAX_ORDER];
    // ...
};
```

## 계층 구조
```
Node (NUMA)
  ↓
Zone (DMA, NORMAL, HIGHMEM, ...)
  ↓
free_area[0..10] (크기별: 4KB, 8KB, 16KB, ..., 4MB)
  ↓
free_list[MIGRATE_TYPES] (타입별: UNMOVABLE, MOVABLE, ...)
  ↓
[페이지] → [페이지] → [페이지] → ...

구체적 예시

// ZONE_NORMAL에서 8KB 메모리 할당

struct zone *zone = &NODE_DATA(0)->node_zones[ZONE_NORMAL];
//                                           ↑
//                                     물리적 위치 (Zone)

struct free_area *area = &zone->free_area[1];
//                                        ↑
//                                    크기 (8KB = 2^1)

struct list_head *list = &area->free_list[MIGRATE_MOVABLE];
//                                         ↑
//                                 이동 가능성 (Type)

// 실제 페이지 추출
page = list_first_entry_or_null(list, struct page, lru);
```

## 메모리 레이아웃
```
ZONE_DMA (0-16MB)
├─ free_area[0]
│  ├─ free_list[MIGRATE_UNMOVABLE]
│  ├─ free_list[MIGRATE_MOVABLE]
│  └─ ...
├─ free_area[1]
│  ├─ free_list[MIGRATE_UNMOVABLE]
│  └─ ...
└─ ...

ZONE_NORMAL (16MB-4GB)
├─ free_area[0]
│  ├─ free_list[MIGRATE_UNMOVABLE]
│  ├─ free_list[MIGRATE_MOVABLE]
│  └─ ...
├─ free_area[1]
│  ├─ free_list[MIGRATE_UNMOVABLE]
│  └─ ...
└─ ...

ZONE_HIGHMEM (4GB 이상)
├─ free_area[0]
│  ├─ free_list[MIGRATE_UNMOVABLE]
│  └─ ...
└─ ...

커널 코드에서

// mm/page_alloc.c
static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
                       int alloc_flags, const struct alloc_context *ac)
{
    struct zoneref *z;
    struct zone *zone;
    struct page *page = NULL;
    
    // 1. Zone 순회 (DMA → NORMAL → ...)
    for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
                                    ac->highest_zoneidx, ac->nodemask) {
        // 2. free_area[order] 선택
        // 3. free_list[migratetype] 선택
        // 4. 페이지 추출
    }
    
    return page;
}

정리

항목기준종류
Zone 물리적 위치 DMA, NORMAL, HIGHMEM, ...
free_area[order] 메모리 크기 4KB, 8KB, 16KB, ..., 4MB
MIGRATE_TYPES 페이지 속성/이동성 UNMOVABLE, MOVABLE, ...

MIGRATE_TYPES는 Zone과 무관하게, 각 Zone의 모든 free_area에서 타입별로 페이지를 분류하는 것입니다!

'linux' 카테고리의 다른 글

/proc/meminfo와 zoneinfo의 관계  (0) 2025.12.28
/proc/zoneinfo 해석 방법  (0) 2025.12.28
raspberry pi 4 커널 빌드 및 교체 시 주의 사항  (0) 2025.12.26
gst와 omx IL의 관계  (0) 2022.11.03
fs.protected_regular  (0) 2022.10.04
Posted by easy16