calculate_totalreserve_pages()是内存管理初始化阶段用于计算系统总保留页数(totalreserve_pages)的函数。它遍历所有 zone,把每个 zone 的保留内存汇总到全局变量totalreserve_pages中,供内存热插拔、水位判断和内存可用性评估使用。
核心作用与背景
totalreserve_pages是一个全局变量,记录系统中不能被常规分配使用的保留页总数。它由三部分构成:
lowmem_reserve[]:前面讲过的低端内存保留——低端 zone 为保护自己而保留的页数;WMARK_MIN水位线:每个 zone 的最低保留水位;nr_reserved_highatomic:为高阶原子分配保留的页数。
这个汇总值用于:
内存热插拔:判断下线内存后是否仍有足够的保留内存;
si_meminfo()//proc/meminfo:计算MemAvailable等字段;OOM 决策:评估系统实际可用的内存量。
典型实现
static void calculate_totalreserve_pages(void) { struct pglist_data *pgdat; unsigned long reserve_pages = 0; enum zone_type i, j; for_each_online_pgdat(pgdat) { pgdat->totalreserve_pages = 0; for (i = 0; i < MAX_NR_ZONES; i++) { struct zone *zone = pgdat->node_zones + i; long max = 0; if (!populated_zone(zone)) continue; /* 累加 lowmem_reserve */ for (j = i; j < MAX_NR_ZONES; j++) { if (populated_zone(pgdat->node_zones + j)) max += zone->lowmem_reserve[j]; } /* 加上 WMARK_MIN 水位 */ max += wmark_pages(zone, WMARK_MIN); /* 加上高阶原子保留 */ max += zone->nr_reserved_highatomic; pgdat->totalreserve_pages += max; reserve_pages += max; } } totalreserve_pages = reserve_pages; }逐步解析
1. 遍历所有在线节点和 zone
for_each_online_pgdat(pgdat) { pgdat->totalreserve_pages = 0; for (i = 0; i < MAX_NR_ZONES; i++) {外层遍历 NUMA 节点,内层遍历每个节点上的 zone 类型。
2. 累加lowmem_reserve
for (j = i; j < MAX_NR_ZONES; j++) { if (populated_zone(pgdat->node_zones + j)) max += zone->lowmem_reserve[j]; }zone->lowmem_reserve[j]:当来自jzone 的分配回退到izone 时,izone 要保留的页数。从
j = i开始遍历到最高 zone,把所有相关的高端 zone 对应的保留量累加。这确保
totalreserve_pages反映最坏情况下低端 zone 需要保留的总量。
3. 加上WMARK_MIN
max += wmark_pages(zone, WMARK_MIN);
WMARK_MIN是 zone 的最低水位线——低于这个值,直接回收/OOM 就会触发。这部分内存不能被常规分配使用,必须计入保留。
4. 加上nr_reserved_highatomic
max += zone->nr_reserved_highatomic;
为高阶原子分配保留的 pageblock 页数。这些页普通分配不能用,也必须计入保留。
5. 汇总到全局变量
pgdat->totalreserve_pages += max; reserve_pages += max;
同时更新节点级的
pgdat->totalreserve_pages和全局的reserve_pages。循环结束后,把全局汇总值写入
totalreserve_pages。
调用场景
它主要在以下时机被调用:
setup_per_zone_wmarks():水位初始化/调整后,重新计算总保留;setup_per_zone_lowmem_reserve():lowmem reserve 更新后;内存热插拔:节点上线/下线后;
CPU 热插拔:影响水位计算时;
sysctl 修改:调整
min_free_kbytes、lowmem_reserve_ratio、watermark_scale_factor等参数后;calculate_min_free_kbytes():计算最小空闲内存时。
总结
calculate_totalreserve_pages()是系统保留内存的汇总器:它遍历所有在线节点和 populated zone,把每个 zone 的lowmem_reserve、WMARK_MIN水位和nr_reserved_highatomic累加,得到节点级和全局的totalreserve_pages。这个值反映了系统中不能被常规分配使用的保留内存总量,是内存热插拔判断、/proc/meminfo统计和 OOM 决策的重要基准。