zoneinfo는 zone의 범위와 통계, buddyinfo는 order별 free block 분포를 보여 줍니다. 같은 zone을 조사하더라도 열의 단위부터 다릅니다. PCP에 있는 page까지 살펴보려면 해당 version의 free counter가 어느 범위를 세는지도 구분해야 합니다.
아래 숫자는 읽는 방법을 설명하기 위해 새로 만든 예제입니다. 실제 장비의 측정값이나 책의 출력값을 옮긴 것이 아닙니다. Base page는 4 KiB, pageblock order는 9, CPU는 두 개라고 가정하겠습니다. 출력은 필요한 field만 선택했으며 모든 counter를 더해 전체 RAM을 만드는 표가 아닙니다.
Node 통계와 zone 통계의 범위를 먼저 나눕니다
/proc/zoneinfo에서 node 통계는 해당 node의 첫 populated zone에 표시됩니다. 그 위치가 DMA zone 아래라고 해서 nr_file_pages를 DMA 전용 counter로 읽으면 안 됩니다. System 전체의 /proc/vmstat과도 범위가 다릅니다. Linux v6.12에서는 zoneinfo_show()와 zoneinfo_show_print()에서 출력 경로를 확인할 수 있습니다.
Node 0, zone Normal
per-node stats
nr_inactive_anon 900
nr_active_anon 100
nr_file_pages 320
nr_dirty 8
nr_writeback 0
nr_shmem 20
nr_dirtied 150
nr_written 142
nr_kernel_stack 64
nr_page_table_pages 12
nr_dirty는 현재 상태이고 nr_dirtied는 누적 event 성격입니다. nr_written과 현재 dirty 양의 단순 차이가 항상 맞아야 하는 것은 아닙니다. 서로 다른 시점의 갱신과 reclaim·redirty 등 다른 경로가 있습니다. 또한 이름이 nr_로 시작한다고 모두 page 개수는 아닙니다. 여기서 nr_kernel_stack은 KiB이고, nr_page_table_pages는 base pages입니다.
nr_file_pages에는 shmem 성격의 page가 포함될 수 있으므로 nr_shmem을 독립적인 추가 pool처럼 무조건 더하지 않습니다. 같은 숫자를 두 번 더하는 문제는 단위 오류와 별개입니다.
Zone의 범위와 allocator가 관리하는 양이 다릅니다
Node 0, zone Normal
pages free 1184
boost 0
min 32
low 48
high 64
spanned 8192
present 7680
managed 7168
protection: (0, 0, 0, 0)
nr_free_pages 1184
pagesets
cpu: 0
count: 8
high: 32
batch: 4
vm stats threshold: 4
cpu: 1
count: 8
high: 32
batch: 4
vm stats threshold: 4
node_unreclaimable: 0
start_pfn: 1048576
spanned 8,192 pages는 zone이 가로지르는 physical address 범위입니다. 그 안에서 존재하는 memory가 present 7,680 pages, allocator가 관리하는 memory가 managed 7,168 pages라고 가정했습니다. Hole이나 관리 대상에서 제외한 memory가 있으므로 세 값은 같지 않습니다. managed에는 이미 할당된 page도 들어갑니다. pages free의 1,184 pages와 혼동하지 않으셔야 합니다.
start_pfn은 개수가 아니라 시작 PFN입니다. 이 예에서 1048576 * 4096은 4 GiB physical address입니다. node_unreclaimable: 0은 모든 allocation이 성공한다는 보증이 아니며, 1이라고 모든 page의 회수를 영원히 금지하는 flag도 아닙니다. Reclaim 실패 상태를 나타내는 해당 version의 출력 조건을 확인해야 합니다.
min/low/high는 allocation·reclaim의 watermark 판단과 연결되지만, free가 특정 숫자를 지났다는 사실 하나로 다음 동작을 확정할 수는 없습니다. GFP 조건, order, protection reserve, 다른 zone과 허용된 node, watermark boost 등도 영향을 줍니다. 이 예의 protection은 모두 0으로 두었습니다. 실제 lowmem reserve는 요청의 classzone에 맞는 열을 골라야 합니다.
PCP의 count와 통계 threshold는 다릅니다
CPU별 count 8은 그 PCP에 있는 base pages입니다. Order가 높은 block을 보관한다면 block 하나가 아니라 포함하는 base pages 수로 합산합니다. 이 예에서는 두 CPU에 합계 16 pages, 즉 64 KiB가 있습니다.
high는 cache 유지·반환 판단과 연결되고 batch는 buddy와 주고받는 단위의 기준입니다. high를 RAM 사용량으로 더하거나, 모든 반환이 언제나 정확히 batch pages라고 가정하지 않습니다. Linux v6.12에서는 high의 최소·최대와 동적 조정도 관련됩니다.
vm stats threshold는 per-CPU 통계의 차이를 묶어서 global counter로 반영하는 기준입니다. Free page를 보관하는 PCP list 자체와 다른 자료입니다. 두 이름에 CPU가 들어간다는 이유로 threshold를 PCP의 추가 free pages로 더하면 안 됩니다.
Buddy의 숫자는 page가 아니라 block 개수입니다
같은 가상 상황의 /proc/buddyinfo를 다음처럼 두겠습니다. 왼쪽부터 order 0-10입니다.
Node 0, zone Normal 0 0 0 0 0 1 0 1 0 0 1
| Order | Free block 수 | Base pages | 크기 |
|---|---|---|---|
| 5 | 1 | 32 | 128 KiB |
| 7 | 1 | 128 | 512 KiB |
| 10 | 1 | 1024 | 4 MiB |
| 합계 | 3 | 1184 | 4736 KiB |
계산은 sum(block_count[order] * 2^order)입니다. 이 예에서는 buddy의 1,184 pages와 PCP의 16 pages를 구분할 수 있습니다. Linux v6.12의 NR_FREE_PAGES 갱신 경로에서는 buddy에서 PCP로 옮길 때 해당 counter에서 차감합니다. 위 pages free는 이 범위에 맞춰 1,184로 두었습니다. Buddy와 PCP를 합쳐 물리적으로 free인 1,200 pages를 계산할 수는 있지만, 그 값을 같은 범위의 NR_FREE_PAGES라고 부르면 안 됩니다. Free memory의 물리적 위치와 특정 counter의 accounting 범위가 다르기 때문입니다.
실제 조사를 할 때는 이 파일들이 동시에 촬영한 snapshot이 아니라는 점까지 고려합니다. PCP를 전부 비우거나 통계를 반복해서 refresh하는 조작 없이도, 먼저 각각 어떤 list와 counter를 출력하는지 확인할 수 있습니다. buddyinfo의 구현은 frag_show()와 frag_show_print()에서 시작합니다.
Pagetypeinfo의 두 표는 다른 것을 셉니다
위 buddy 분포를 migrate type으로 나누면 다음처럼 구성할 수 있습니다. Free pages count라는 heading이 있어도 각 order 열은 free block 개수입니다.
Page block order: 9
Pages per block: 512
Free pages count per migrate type at order 0 1 2 3 4 5 6 7 8 9 10
Node 0, zone Normal, type Unmovable 0 0 0 0 0 1 0 0 0 0 0
Node 0, zone Normal, type Movable 0 0 0 0 0 0 0 1 0 0 1
Node 0, zone Normal, type Reclaimable 0 0 0 0 0 0 0 0 0 0 0
Node 0, zone Normal, type HighAtomic 0 0 0 0 0 0 0 0 0 0 0
Number of blocks type Unmovable Movable Reclaimable HighAtomic
Node 0, zone Normal 2 11 2 0
앞의 free-list 표에서 type별 열을 더하면 buddy 분포와 맞습니다. 뒤의 Number of blocks는 free block이 아니라 pageblock의 migrate-type 배정 수입니다. 이미 할당된 부분도 포함하므로 15 * 2 MiB를 현재 사용 가능한 free memory라고 읽으면 안 됩니다. Pageblock 배정 수를 managed와 무조건 일치시키는 계산도 피해야 합니다. Hole과 zone 경계, 실제 pageblock 순회 조건이 관여합니다.
Free-list 표는 pagetypeinfo_showfree_print(), pageblock 배정 표는 pagetypeinfo_showblockcount_print()에서 확인할 수 있습니다. CMA 등 추가 type과 CONFIG_PAGE_OWNER 관련 출력은 실제 configuration에 따라 달라집니다. Migrate type은 fragmentation을 줄이기 위한 배치 분류이지, 그 type의 모든 page가 언제나 즉시 이동 가능하다는 보증은 아닙니다.
참고 자료
- Lorenzo Stoakes, The Linux Memory Manager, Early Access edition, 2025, §14.5.1. 출력 예제와 계산은 독립적으로 구성했습니다.
- Linux v6.12
mm/vmstat.c: zone, buddy, migrate-type별 출력입니다. - Linux v6.12
mm/page_alloc.c: free list와 PCP 이동 시의 accounting입니다. - Linux v6.12
/procdocumentation