Linux内核内存管理初探:Memblock机制详解

Linux内核内存管理初探:Memblock机制详解

linux-insides-zh Linux 内核揭秘 linux-insides-zh 项目地址: https://gitcode.com/gh_mirrors/lin/linux-insides-zh

前言

内存管理是操作系统内核中最复杂且关键的子系统之一。在Linux内核启动初期,当通用内存分配器尚未就绪时,内核需要一种机制来管理物理内存。本文将深入探讨Linux内核早期使用的内存管理机制——Memblock(内存块)。

内存管理概述

在Linux内核启动过程中,start_kernel函数负责初始化所有内核特性。在此之前,内核已经建立了初期页表、识别页表和固定映射页表,但完整的内存管理系统尚未启动。Memblock机制正是在这个过渡阶段发挥重要作用。

Memblock基础概念

Memblock最初被称为"逻辑内存块",后经Yinghai Lu的补丁改进并更名为现在的名称。它是x86_64架构上内核早期使用的内存管理方法。

核心数据结构

Memblock系统主要由三个关键数据结构组成:

  1. memblock:顶层结构,包含整个内存块的全局信息
  2. memblock_type:描述特定类型的内存区域集合
  3. memblock_region:描述单个内存区域
1. memblock结构
struct memblock {
    bool bottom_up;          // 内存分配方向标志
    phys_addr_t current_limit; // 当前内存限制
    struct memblock_type memory;   // 可用内存区域
    struct memblock_type reserved; // 保留内存区域
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
    struct memblock_type physmem;  // 物理内存映射
#endif
};
2. memblock_type结构
struct memblock_type {
    unsigned long cnt;       // 当前区域数量
    unsigned long max;       // 最大区域容量
    phys_addr_t total_size;  // 所有区域总大小
    struct memblock_region *regions; // 区域数组指针
};
3. memblock_region结构
struct memblock_region {
    phys_addr_t base;        // 区域基地址
    phys_addr_t size;        // 区域大小
    unsigned long flags;     // 区域标志
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
    int nid;                 // NUMA节点ID
#endif
};

Memblock初始化过程

Memblock的初始化在内核启动早期完成。全局的memblock实例定义如下:

struct memblock memblock __initdata_memblock = {
    .memory.regions = memblock_memory_init_regions,
    .memory.cnt = 1,
    .memory.max = INIT_MEMBLOCK_REGIONS,
    .reserved.regions = memblock_reserved_init_regions,
    .reserved.cnt = 1,
    .reserved.max = INIT_MEMBLOCK_REGIONS,
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
    .physmem.regions = memblock_physmem_init_regions,
    .physmem.cnt = 1,
    .physmem.max = INIT_PHYSMEM_REGIONS,
#endif
    .bottom_up = false,
    .current_limit = MEMBLOCK_ALLOC_ANYWHERE,
};

关键点说明:

  • __initdata_memblock宏控制memblock数据在内核初始化后的处理方式
  • 初始内存区域数组大小为128(由INIT_MEMBLOCK_REGIONS定义)
  • 默认内存分配方向为自顶向下
  • 初始内存限制设置为最大可能值(MEMBLOCK_ALLOC_ANYWHERE

Memblock核心API

Memblock提供了一系列API来管理内存区域,主要包括:

1. 添加内存区域

memblock_add
int memblock_add(phys_addr_t base, phys_addr_t size)
{
    return memblock_add_range(&memblock.memory, base, size,
                             MAX_NUMNODES, 0);
}

该函数将新的可用内存区域添加到memblock中,实际工作由memblock_add_range完成。

memblock_add_range

这是内存添加的核心函数,主要流程:

  1. 计算区域结束地址(考虑地址溢出)
  2. 检查与现有区域的重叠情况
  3. 处理不重叠部分
  4. 合并相邻区域

关键操作包括:

  • 使用memblock_cap_size确保地址不溢出
  • 通过memblock_double_array扩展区域数组(如果需要)
  • 使用memblock_insert_region插入新区域
  • 调用memblock_merge_regions合并相邻区域

2. 保留内存区域

memblock_reserve
int memblock_reserve(phys_addr_t base, phys_addr_t size)
{
    return memblock_add_range(&memblock.reserved, base, size,
                             MAX_NUMNODES, 0);
}

memblock_add类似,但操作的是保留内存区域。

3. 其他重要API

  • memblock_remove:从内存块中移除内存区域
  • memblock_find_in_range:在指定范围内查找可用区域
  • memblock_free:释放内存块中的区域
  • for_each_mem_range:遍历内存区域

内存区域信息获取

Memblock提供了获取已分配内存信息的API:

phys_addr_t __init_memblock get_allocated_memblock_memory_regions_info(
    phys_addr_t *addr)
{
    if (memblock.memory.regions == memblock_memory_init_regions)
        return 0;
    
    *addr = __pa(memblock.memory.regions);
    
    return PAGE_ALIGN(sizeof(struct memblock_region) *
           memblock.memory.max);
}

类似地,get_allocated_memblock_reserved_regions_info可用于获取保留区域信息。

调试支持

Memblock提供了多种调试手段:

1. 内核日志输出

通过在内核命令行添加memblock=debug参数,可以启用详细日志输出:

#define memblock_dbg(fmt, ...) \
    if (memblock_debug) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)

2. Debugfs接口

在支持debugfs的系统上,可以通过以下路径查看memblock状态:

  • /sys/kernel/debug/memblock/memory
  • /sys/kernel/debug/memblock/reserved
  • /sys/kernel/debug/memblock/physmem

实际应用示例

在内核初始化过程中,memblock_x86_fill函数使用e820提供的内存映射信息,通过memblock_add将内核保留的内存区域添加到memblock中。

总结

Memblock机制作为Linux内核早期内存管理的关键组件,为内核启动阶段提供了基本但可靠的内存管理能力。通过理解Memblock的数据结构和API,我们可以更深入地掌握Linux内存管理系统的初始化和工作流程。随着内核初始化的进行,Memblock最终会被更复杂的内存管理系统所取代,但其在启动阶段的作用不可替代。

linux-insides-zh Linux 内核揭秘 linux-insides-zh 项目地址: https://gitcode.com/gh_mirrors/lin/linux-insides-zh

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仰北帅Bobbie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值