ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

init mem_init

init mem_init mem_init是 x86-64 架构内存初始化流程中的收官函数位于arch/x86/mm/init_64.c。它在伙伴系统buddy allocator已经就绪之后被调用负责完成几项关键的“收尾”工作将系统从“启动模式”正式切换到“运行模式”。核心作用启动模式到运行模式的切换这个函数执行时memblock已经把空闲内存全部释放给了伙伴系统。此时需要做的是标记启动阶段结束、注册特殊内存区域、预分配页表页为后续进程管理铺平道路。逐行解析void __init mem_init(void) { /* clear_bss() already clear the empty_zero_page */ after_bootmem 1; x86_init.hyper.init_after_bootmem();after_bootmem 1这是最关键的标志切换。这个标志决定了内存分配走memblock_alloc()还是get_zeroed_page()。置为 1 后所有分配都走伙伴系统路径。x86_init.hyper.init_after_bootmem()调用 Hypervisor 相关的钩子。在 Xen 等虚拟化环境下此时需要通知 Hypervisor 完成一些收尾工作如释放早期预留的页表页。register_page_bootmem_info();register_page_bootmem_info()为 NUMA 节点或大页优化场景注册 bootmem 元数据。注释解释了为什么必须放在这里因为此时memblock_free_all()已经将所有保留的延迟页初始化完毕可以安全地操作这些struct page了。if (get_gate_vma(init_mm)) kclist_add(kcore_vsyscall, (void *)VSYSCALL_ADDR, PAGE_SIZE, KCORE_USER);注册 vsyscall 页面到/proc/kcore如果 vsyscall 页面存在get_gate_vma返回非空将其添加到 kcore 列表类型为KCORE_USER。这让调试工具能通过/proc/kcore读取这个特殊页面。preallocate_vmalloc_pages(); }preallocate_vmalloc_pages()预分配 vmalloc 区域的顶层页表页。它的目的是避免运行时昂贵的页表同步操作让所有进程创建时直接继承这些预分配的页表页。在启动流程中的位置setup_arch() ├── paging_init() // 建立内存管理数据结构 └── ... mem_init() // ← 启动模式 → 运行模式 ├── after_bootmem 1 ├── register_page_bootmem_info() ├── kclist_add(vsyscall) └── preallocate_vmalloc_pages()mem_init()执行完毕后内核的内存管理子系统就完全就绪了。后续的mm_init()会初始化 SLAB/SLUB 分配器、页表缓存等更高级的机制然后内核就可以开始创建用户进程了。为什么这些工作要放在这里这个函数的每一项工作都有一个共同特点它们都必须在伙伴系统就绪之后、但在任何用户进程创建之前完成。after_bootmem 1必须在 memblock 释放完内存后设置。register_page_bootmem_info()必须在memblock_free_all()初始化完所有延迟页之后调用。preallocate_vmalloc_pages()必须在第一个用户进程创建之前完成否则该进程的页表会缺少 vmalloc 区域的顶层条目。这个函数是 x86-64 内存初始化的“最后一公里”完成后系统就真正具备了管理内存和创建进程的能力。
返回列表