Linux 内核中的**内存管理模块(Memory Management, MM)**从初始化到可供其他模块使用,需要经历一系列严格的阶段,涵盖硬件初始化、数据结构构建、接口暴露等过程。以下是关键阶段的详细说明:
关键函数调用链(示例)
start_kernel()
→ setup_arch() # 架构相关内存初始化
→ mm_init() # 核心内存管理初始化
→ mem_init() # 释放memblock到伙伴系统
→ kmem_cache_init() # SLAB初始化
→ vmalloc_init() # 虚拟内存区域初始化
→ rest_init() # 启动kswapd线程
1. 硬件相关初始化(Architecture-Specific Setup)
阶段目标:检测物理内存布局,建立最基本的页表映射。
- 执行时机:内核启动早期(
start_kernel()之前,由汇编代码处理)。 - 关键步骤:
- 探测物理内存
- BIOS/UEFI 或设备树(DT)传递内存信息(如
mem=内核参数)。 - 记录内存区域(
memblock或e820映射,位于arch/x86/kernel/e820.c)。
- BIOS/UEFI 或设备树(DT)传递内存信息(如
- 初始化页表
- 建立临时内核页表(
arch/x86/mm/init_64.c的startup_64())。 - 启用分页机制(
cr3寄存器加载)。
- 建立临时内核页表(
- 保留关键内存区域
- 保留内核代码、数据段、启动参数等(
memblock_reserve())。
- 保留内核代码、数据段、启动参数等(
- 探测物理内存
边界:
- 依赖体系结构代码(如
arch/x86,arch/arm64)。 - 不依赖其他内核模块(此时调度器、驱动等尚未初始化)。
2. 通用内存管理子系统初始化(start_kernel() 阶段)
阶段目标:构建核心内存管理数据结构,替换临时分配器。
- 执行时机:
start_kernel()→mm_init()。 - 关键步骤:
- 初始化
memblock分配器- 临时管理物理内存(
mm/memblock.c),后续被伙伴系统取代。
- 临时管理物理内存(
- 建立伙伴系统(Buddy System)
- 解析
memblock内存区域,初始化struct zone(mm/page_alloc.c的free_area_init())。 - 划分物理页帧(
struct page数组),管理空闲列表。
- 解析
- 初始化 SLAB/SLUB 分配器
- 为内核对象(如
task_struct)创建缓存(mm/slub.c的kmem_cache_init())。
- 为内核对象(如
- 设置内存回收机制
- 启动
kswapd内核线程(mm/vmscan.c)。
- 启动
- 初始化虚拟内存(VM)
- 建立
vmalloc区域(mm/vmalloc.c的vmalloc_init())。
- 建立
- 初始化
边界:
- 依赖体系结构代码提供的物理内存信息。
- 不依赖动态模块(此时模块子系统未初始化)。
3. 动态内存接口暴露(API Ready)
阶段目标:提供其他模块可调用的内存分配接口。
- 执行时机:
mm_init()完成后,其他子系统开始初始化。 - 关键接口:
- 物理页分配
alloc_pages()/__get_free_pages()(include/linux/gfp.h)。
- SLAB 分配器
kmalloc()/kfree()(include/linux/slab.h)。
- 虚拟内存映射
vmalloc()/vfree()(mm/vmalloc.c)。
- DMA 内存接口
dma_alloc_coherent()(include/linux/dma-mapping.h)。
- 用户空间内存交互
copy_to_user()/get_user_pages()(mm/memory.c)。
- 物理页分配
边界:
- 通过
EXPORT_SYMBOL()导出符号供其他模块使用。 - 依赖核心模块(如
spinlock用于保护内存结构)。
4. 与其他模块的协作(Integration)
阶段目标:响应其他模块的内存需求。
- 示例场景:
- 进程管理模块
- 创建进程时调用
mm_init()初始化mm_struct(kernel/fork.c)。
- 创建进程时调用
- 文件系统模块
- 文件映射(
mmap())触发filemap_fault()加载页面缓存。
- 文件映射(
- 设备驱动模块
- 驱动通过
kmalloc()分配内存,或ioremap()映射设备内存。
- 驱动通过
- 网络模块
- SKB 缓冲区分配(
alloc_skb()内部调用kmalloc())。
- SKB 缓冲区分配(
- 进程管理模块
边界:
- 严格通过头文件中的 API 交互,避免直接访问内部数据结构。
5. 动态内存扩展(可选)
阶段目标:支持内存热插拔、CMA(连续内存分配器)等高级功能。
- 执行时机:运行时动态加载。
- 关键步骤:
- 内存热插拔
- 通过
add_memory()/remove_memory()动态增删内存(drivers/base/memory.c)。
- 通过
- CMA 初始化
- 为设备预留连续内存(
mm/cma.c的cma_init_reserved_areas())。
- 为设备预留连续内存(
- 内存热插拔
边界:
- 依赖设备驱动模块(如 NUMA 架构)。
总结:从无到有的阶段
| 阶段 | 关键操作 | 依赖关系 |
|---|---|---|
| 硬件初始化 | 探测内存、建立页表 | 仅依赖体系结构代码 |
| 核心内存子系统初始化 | 伙伴系统、SLAB、VM初始化 | 依赖硬件初始化完成 |
| 接口暴露 | 导出 kmalloc、alloc_pages 等符号 | 依赖核心内存子系统 |
| 模块协作 | 为进程、文件系统、驱动提供内存服务 | 所有基础接口已就绪 |
| 动态扩展 | 内存热插拔、CMA | 可选,依赖具体需求 |
内存模块的初始化是内核启动的关键路径之一,必须按严格顺序执行,确保其他模块在需要内存时,底层机制已完全就绪。
3239

被折叠的 条评论
为什么被折叠?



