当前位置: 首页 > news >正文

深入理解 Slab / Buddy 分配器与 MMU 映射机制


📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry


深入理解 Slab / Buddy 分配器与 MMU 映射机制

在现代 Linux 内核中,物理内存的管理和虚拟地址的映射是系统性能和资源调度的核心。本文将系统讲解 Slab 分配器和 Buddy 分配器如何管理物理内存,并进一步分析 MMU 如何通过四级页表将这些物理内存映射到虚拟地址空间。


在这里插入图片描述

一、Buddy 分配器:以页为单位的物理内存管理

Buddy 分配器是 Linux 核心的物理页分配器,它以 2^n 页为单位分配连续的内存块,适合于大块内存分配需求。

基本功能

  • 分配单位:1 页 = 4KB (x86_64)
  • 支持 2^n 页的分配(如 4KB, 8KB, 16KB, …, 1MB 等)
  • 重构形成 Buddy 对,便于合并和释放

示例

请求 16KB 内存:

alloc_pages(GFP_KERNEL, 2)  // 2^2 = 4 页 = 16KB

返回一个连续的 16KB 物理地址指针


二、Slab 分配器:对象级别的内存管理

Slab 分配器用于小块内存分配,不能简单通过 buddy 分配器分配不同颜色大小的内存块。Slab 通常依赖于 buddy 分配器进行基础页分配,然后将页内分割为小对象。

示例

kmalloc(64, GFP_KERNEL) // 分配 64 字节
  • slab 分配器会找到 64-byte 的 cache
  • 如果无空,则从 buddy 分配 1 页 (4KB)
  • 切割为 64-byte * 64 个对象

三、MMU 与四级页表映射机制

由于操作系统对多连续和线性虚拟内存的需求,需要通过四级页表把虚拟地址 (VA) 映射成物理地址 (PA),用于 MMU 转换。

四级页表结构详解(以 x86_64 为例)

页表级别位数索引项数控制范围
PGD(顶层)9512512 GB
PUD(上层)95121 GB
PMD(中间)95122 MB
PTE(底层)95124 KB
页内偏移12-4 KB

48 位虚拟地址 = 9 + 9 + 9 + 9 + 12

四级页表拆解结构图:

|<----- 9 ---->|<---- 9 ---->|<---- 9 ---->|<---- 9 ---->|<-- 12 -->|
+--------------+-------------+-------------+-------------+----------+
| PGD Index    | PUD Index   | PMD Index   | PTE Index   | Offset   |
+--------------+-------------+-------------+-------------+----------+
  • PGD:Page Global Directory(页全局目录)
  • PUD:Page Upper Directory(页上级目录)
  • PMD:Page Middle Directory(页中级目录)
  • PTE:Page Table Entry(页表项)
  • Offset:页内偏移

四级页表查找流程图

graph TD;A[虚拟地址 (VA)] --> B[CR3 - PGD 基地址]B --> C[PGD 索引]C --> D[PUD 索引]D --> E[PMD 索引]E --> F[PTE 索引]F --> G[页框号 + Offset 得到物理地址]

四级页表转换详细步骤

  1. CR3 寄存器中保存 PGD(页全局目录)的物理地址。
  2. 取虚拟地址的高 9 位,找到 PGD 的索引项,得到下一级 PUD 的物理地址。
  3. 取虚拟地址次高 9 位,找到 PUD 的索引项,得到下一级 PMD 的物理地址。
  4. 再取 9 位,查找 PMD 的索引项,获得 PTE 的物理地址。
  5. 最低的 9 位用于查找 PTE 表中的页表项(含物理页框号 PFN)。
  6. 最后的 12 位页内偏移,加到物理页框基地址上,形成最终物理地址。

示例:虚拟地址到物理地址

假设虚拟地址为:0x00007F12_3456789A

分解:

  • PGD 索引:[47:39] = 0x0F
  • PUD 索引:[38:30] = 0x3C
  • PMD 索引:[29:21] = 0x15
  • PTE 索引:[20:12] = 0x1A
  • Offset:[11:0] = 0x89A

假设每级查找后页表物理地址分别如下:

  1. PGD[0x0F] -> PUD @ 0x00200000
  2. PUD[0x3C] -> PMD @ 0x00300000
  3. PMD[0x15] -> PTE @ 0x00400000
  4. PTE[0x1A] -> PFN = 0x00500000

最终物理地址:

0x00500000 + 0x89A = 0x0050089A
完整映射流程(结构示意图):
graph TD;VA[虚拟地址 0x00007F12_3456789A]VA --> PGD[PGD[0x0F] @ 0x00100000]PGD --> PUD[PUD[0x3C] @ 0x00200000]PUD --> PMD[PMD[0x15] @ 0x00300000]PMD --> PTE[PTE[0x1A] @ 0x00400000]PTE --> PA[物理页框 0x00500000]PA --> FINAL[最终物理地址 0x0050089A]

四、Slab/Buddy 分配与 MMU 映射的关系

  1. Buddy 分配器分配物理页,供:

    • 用户端虚拟内存(进程空间)
    • 内核空间内存(kmalloc/slab/cache)
    • 内核模块、页表、内核堆栈等
  2. Slab 分配器依赖 buddy 分配页,将页切割为对象,重用已分配物理内存块

  3. MMU + 四级页表完成虚拟地址空间到这些物理页的映射。进程或内核访问虚拟地址时,MMU 通过四级页表找到实际物理页,实现隔离、保护和高效内存访问。


五、核心要点总结

  • Buddy / Slab 都分配物理内存,只不过粒度和用途不同
  • 虚拟地址通过四级页表结构映射到物理地址,MMU 保证进程空间隔离和内存保护
  • 四级页表结构的每一级都影响性能和内存消耗,实际 Linux 支持巨页(1GB/2MB)减少多级查表

六、参考流程图

graph TD;U[用户/内核分配虚拟内存] --> K[Slab/Buddy 向内核申请物理页]K --> MMU[MMU 建立虚拟到物理映射(四级页表)]MMU --> X[进程/内核通过虚拟地址访问数据]X --> MMU2[MMU 查页表,定位物理地址]MMU2 --> RAM[物理内存访问]


📖 推荐阅读:《Yocto项目实战教程:高效定制嵌入式Linux系统》
🎥 更多学习视频请关注 B 站:嵌入式Jerry


http://www.xdnf.cn/news/1217467.html

相关文章:

  • 【源力觉醒 创作者计划】对比与实践:基于文心大模型 4.5 的 Ollama+CherryStudio 知识库搭建教程
  • mysql结构对比工具
  • 类与对象(上),咕咕咕
  • ECMAScript2024(ES15)新特性
  • SpringAI 1.0.0发布:打造企业级智能聊天应用
  • AI 安监系统:为工业园安全保驾护航
  • 【Debian】4-‌1 Gitea简介以及与其他git方案差异
  • Windows 10 WSLUbuntu 22.04 安装并迁移到 F 盘
  • 2018 年 NOI 最后一题题解
  • 【预判一手面试问题:排序】
  • 2023 年 NOI 最后一题题解
  • n8n为什么建议在数组的每个item中添加json键?
  • Docker部署Nacos
  • LeetCode 53 - 最大子数组和
  • Android Emoji 全面解析:从使用到自定义
  • 《嵌入式C语言笔记(十六):字符串搜索、动态内存与函数指针精要》
  • 企业微信API接口发消息实战:从0到1的技术突破之旅
  • MySQL索引和事务笔记
  • 2419.按位与最大的最长子数组
  • JAVAEE--4.多线程案例
  • Mac配置iterm2
  • 【动态规划 | 多状态问题】动态规划求解多状态问题
  • 信贷风控笔记8-解读商业银行资本管理办法笔记
  • Day 4-1: 机器学习算法全面总结
  • Vue路由钩子完全指南
  • 论文阅读|ArxiV 2024|Mamba进一步研究|VSSD
  • Python Pandas.concat函数解析与实战教程
  • 【力扣热题100】哈希——字母异位词分组
  • 20250730在荣品的PRO-RK3566开发板的Android13下调通敦泰的FT8206触控芯片【I2C的挂载】
  • colima 修改镜像源为国内源