mem

mem_map和mem_section的区别

在内核的内存管理中,mem_mapmem_section 是两种不同的机制,主要用于管理物理页(struct page)的映射。它们的区别主要体现在内存模型、适用场景和实现方式上:


1. mem_map

  • 定义
    mem_map 是一个全局的 struct page 数组,直接映射所有物理内存的页帧。每个物理页面对应数组中的一个元素。
  • 内存模型
    用于 平坦内存模型(Flat Memory Model) 或旧版本内核的连续内存管理。
  • 特点
    • 简单直接:物理地址通过简单偏移计算即可转换为 mem_map 的索引。
    • 连续内存假设:假设物理内存是连续的,适用于小内存或物理地址无空洞的场景。
    • 内存浪费:若物理内存存在空洞(如 NUMA 或预留内存),mem_map 仍会为空洞分配 struct page 条目,导致空间浪费。
  • 访问方式
    通过物理地址计算索引(例如:pfn = phys_addr >> PAGE_SHIFTpage = &mem_map[pfn])。

2. mem_section

  • 定义
    mem_section稀疏内存模型(Sparse Memory Model) 的核心结构,将物理内存划分为多个段(Section),每个段管理自己的 struct page 数组。
  • 内存模型
    用于稀疏内存模型(CONFIG_SPARSEMEM),支持非连续物理内存。
  • 特点
    • 灵活高效:按需分配 struct page 数组,仅对实际存在的内存区域分配内存,避免空洞造成的浪费。
    • 支持大内存:适用于物理内存分散或巨大的系统(如 TB 级内存)。
    • 多级查找:物理地址需先定位到对应的 mem_section,再在段内找到 struct page
  • 访问方式
    1. 根据物理地址计算段号(Section Number)。
    2. 通过全局 mem_section 数组找到对应的段。
    3. 在段内的 page 数组中定位具体页结构。

对比总结

特性 mem_map mem_section
内存模型 平坦内存模型(连续内存) 稀疏内存模型(支持非连续内存)
适用场景 小内存、物理地址连续 大内存、物理地址稀疏或非连续
数据结构 全局连续数组 分段管理,每段独立 page 数组
内存开销 可能浪费(为空洞分配条目) 按需分配,节省内存
物理地址转换 直接偏移计算 多级查找(段号 + 段内偏移)
内核配置选项 默认在非稀疏模型中启用 CONFIG_SPARSEMEM

演进背景

  • mem_map 的局限性
    随着内存容量增长和 NUMA 架构普及,物理内存常呈现非连续特性,导致 mem_map 浪费严重。
  • mem_section 的优势
    稀疏模型通过分段管理,动态分配 struct page 内存,显著减少内存开销,成为现代内核(尤其是大内存系统)的默认选择。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
// mem_map 的访问(平坦模型)
struct page *get_page_from_mem_map(unsigned long phys_addr) {
unsigned long pfn = phys_addr >> PAGE_SHIFT;
return &mem_map[pfn];
}

// mem_section 的访问(稀疏模型)
struct page *get_page_from_mem_section(unsigned long phys_addr) {
unsigned long section_nr = (phys_addr >> SECTION_SIZE_BITS);
struct mem_section *section = &mem_section[section_nr];
unsigned long pfn_offset = (phys_addr & SECTION_MASK) >> PAGE_SHIFT;
return section->page[pfn_offset];
}

结论

  • mem_map 适用于简单、连续的物理内存管理,但在现代系统中逐渐被淘汰。
  • mem_section 通过稀疏模型解决了大内存和非连续内存的管理问题,是当前内核的主流方案。