
nr_free_zone_pages()是用于统计指定高位 zone 范围内空闲页总数的辅助函数主要用于/proc/meminfo中FreeSwap之外的MemFree/MemAvailable等统计以及内存回收、水位判断等场景。核心作用与背景它回答的问题是从当前 zone 开始向上更高 zone一共有多少空闲页参数offset指定了起始 zone 的索引函数会统计从该 zone 到ZONE_MOVABLE最高 zone之间的所有空闲页。典型实现static unsigned long nr_free_zone_pages(int offset) { struct zoneref *z; struct zone *zone; /* 只统计比 offset 更高含的 zone 的空闲页 */ unsigned long sum 0; for_each_zone_zonelist_nodemask(zone, z, contig_zonelist, offset, NULL) { if (!populated_zone(zone)) continue; sum zone_page_state(zone, NR_FREE_PAGES); } return sum; }具体实现随版本核心是遍历 zone 并累加NR_FREE_PAGES。关键点解析1.offset参数的含义offset是 zone 索引enum zone_type的值。函数统计的是从offset开始、到最高 zone 为止的所有 zone。例如offset ZONE_NORMAL则统计ZONE_NORMAL、ZONE_HIGHMEM、ZONE_MOVABLE等。这与GFP标志决定的“允许的最高 zone”相反——highest_zoneidx是上限而offset是下限。2.contig_zonelist这是node_zonelist(0, GFP_KERNEL)或类似的东西代表从节点 0 开始的 zonelist。使用 zonelist 遍历宏可以正确处理 NUMA 节点关系。3.zone_page_state(zone, NR_FREE_PAGES)读取 zone 的NR_FREE_PAGES计数。这个计数是 per-CPU 差分的汇总值包含 PCP 缓存和伙伴系统中的空闲页。4.populated_zone()检查跳过没有内存的 zone如某些 NUMA 节点上不存在的ZONE_HIGHMEM。调用场景它主要被以下函数调用1.si_meminfo()/si_mem_available()用于/proc/meminfo的MemFree等字段统计从ZONE_NORMAL开始的空闲页。2.__zone_watermark_ok()的某些变体用于判断从某个 zone 开始的空闲页是否满足水位。3. 内存热插拔 / 回收决策判断高 zone 的空闲页是否足够。与相关函数的关系函数作用nr_free_zone_pages(offset)统计从offset到最高 zone 的空闲页nr_free_buffer_pages()nr_free_zone_pages(GFP_USER)的封装统计用户可用页zone_page_state(zone, NR_FREE_PAGES)单个 zone 的空闲页总结nr_free_zone_pages()是按 zone 范围统计空闲页的辅助函数它遍历从offset指定的 zone 开始到最高 zone 的所有 populated zone累加NR_FREE_PAGES返回总空闲页数。它主要用于/proc/meminfo的统计和内存管理决策是理解系统“有多少可用内存”的基础工具。