资讯动态

page_alloc init_per_zone_wmark_min

发布时间:2026/10/19 7:20:06 来源:尧图企业网站定制
init_per_zone_wmark_min()是内核启动阶段初始化内存水位线watermark的核心函数。它通过core_initcall注册在系统启动时被调用负责根据当前可用的低端内存大小计算出合理的min_free_kbytes并据此为每个 zone 设置WMARK_MIN、WMARK_LOW、WMARK_HIGH三个水位线。核心作用与调用时机该函数在启动流程中通过core_initcall宏被注册。关于它首次调用的时机内核社区曾有过讨论结论是在rest_init()调用模块初始化函数之前系统会有一段时间处于“没有水位线”或水位线为 0 的状态运行这依赖于当时系统有足够的内存且还没有用户进程需要回收。核心逻辑与实现init_per_zone_wmark_min()的完整逻辑如下int __meminit init_per_zone_wmark_min(void) { unsigned long lowmem_kbytes; int new_min_free_kbytes; lowmem_kbytes nr_free_buffer_pages() * (PAGE_SIZE 10); new_min_free_kbytes int_sqrt(lowmem_kbytes * 16); if (new_min_free_kbytes user_min_free_kbytes) { min_free_kbytes new_min_free_kbytes; if (min_free_kbytes 128) min_free_kbytes 128; if (min_free_kbytes 65536) min_free_kbytes 65536; } else { pr_warn(min_free_kbytes is not updated to %d because user defined value %d is preferred\n, new_min_free_kbytes, user_min_free_kbytes); } setup_per_zone_wmarks(); refresh_zone_stat_thresholds(); setup_per_zone_lowmem_reserve(); #ifdef CONFIG_NUMA setup_min_unmapped_ratio(); setup_min_slab_ratio(); #endif return 0; } core_initcall(init_per_zone_wmark_min);逐步解析1. 计算min_free_kbytes的默认值lowmem_kbytes nr_free_buffer_pages() * (PAGE_SIZE 10); new_min_free_kbytes int_sqrt(lowmem_kbytes * 16);nr_free_buffer_pages()前面讲过的统计用户态可用的空闲页总数。PAGE_SIZE 10将页数转换为 KB。核心公式min_free_kbytes 4 * sqrt(lowmem_kbytes)即sqrt(低端内存(KB) × 16)。这个公式让内存越大的系统保留越多的最低空闲内存但保留比例随内存增大而减小。2. 与用户设置比较并钳制范围if (new_min_free_kbytes user_min_free_kbytes) { min_free_kbytes new_min_free_kbytes; if (min_free_kbytes 128) min_free_kbytes 128; if (min_free_kbytes 65536) min_free_kbytes 65536; }只有当自动计算值大于用户设置值user_min_free_kbytes时才采用自动值。范围钳制在[128KB, 65536KB]之间。注意此处代码片段显示上限为 6553664MB但后续内核版本将其提高到了 262144256MB。如果用户设置值更大则保留用户值并打印警告。3. 后续初始化步骤setup_per_zone_wmarks()前面讲过的根据min_free_kbytes和watermark_scale_factor计算各 zone 的WMARK_MIN/LOW/HIGH。refresh_zone_stat_thresholds()刷新 zone 统计的阈值。setup_per_zone_lowmem_reserve()前面讲过的计算各 zone 的lowmem_reserve[]。NUMA 相关setup_min_unmapped_ratio()和setup_min_slab_ratio()仅在 NUMA 配置下执行。与相关函数的关系函数职责init_per_zone_wmark_min()总入口计算min_free_kbytes调用后续初始化setup_per_zone_wmarks()计算各 zone 的_watermark[]setup_per_zone_lowmem_reserve()计算各 zone 的lowmem_reserve[]nr_free_buffer_pages()统计用户可用空闲页历史演进2011 年有补丁修复了在内存热插拔时init_per_zone_wmark_min()会覆盖用户手动设置的min_free_kbytes的问题确保用户设置优先。上限调整min_free_kbytes的上限从早期的 64MB 逐步提高到 256MB以应对现代大内存和高速网卡场景。总结init_per_zone_wmark_min()是内存水位线的启动初始化总入口它通过core_initcall在启动阶段执行计算min_free_kbytes的默认值4 * sqrt(lowmem_kbytes)并与用户设置比较然后依次调用setup_per_zone_wmarks()、setup_per_zone_lowmem_reserve()等函数完成各 zone 水位和保留内存的初始化。它是内存分配器从“无水位运行”过渡到“有水位管理”的关键步骤。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑