第1章:概述
基于 Linux 6.12.38 源码,涵盖物理内存与虚拟内存管理的核心机制
学习目标: 理解 Linux 内存管理的核心概念、架构和数据流
1.1 基础概念
1.1.1 物理地址 vs 虚拟地址
物理地址 (Physical Address):
- 内存硬件上的实际地址
- CPU 通过地址总线直接访问
- 受物理内存大小限制
虚拟地址 (Virtual Address):
- 程序看到的地址空间
- 由 MMU 转换为物理地址
- 可以远大于物理内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| ┌─────────────────────────────────────────────────────────────────┐ │ 地址转换过程示意 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 程序使用虚拟地址: │ │ 0x7fff12345678 │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ MMU │ │ │ │ (地址转换) │ │ │ └──────┬──────┘ │ │ │ │ │ ▼ │ │ 物理地址: 0x87654321 │ │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ 物理内存 │ │ │ └─────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘
|
1.1.2 页式存储管理
Linux 使用页式存储管理,将内存划分为固定大小的块:
| 术语 |
大小 (x86_64) |
描述 |
| 页 (Page) |
4KB |
内存管理的基本单位 |
| 巨页 (Huge Page) |
2MB/1GB |
提高性能,减少 TLB 压力 |
| PTE (Page Table Entry) |
8 bytes |
页表项,存储一个页的映射 |
为什么需要分页?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 不分页的问题: ┌─────────────────────────────────────────────────────────────────┐ │ 问题 1: 碎片化 │ │ ├── 程序 A 需要连续 1MB 内存 │ │ ├── 物理内存有足够空间但不连续 │ │ └── 分配失败 │ │ │ │ 问题 2: 内存保护 │ │ ├── 进程 A 可以访问进程 B 的内存 │ │ └── 安全隐患 │ │ │ │ 问题 3: 地址空间限制 │ │ ├── 32 位系统最多 4GB 地址空间 │ │ └── 无法运行大型程序 │ └─────────────────────────────────────────────────────────────────┘
分页的优势: ┌─────────────────────────────────────────────────────────────────┐ │ 优势 1: 消除碎片化 │ │ ├── 虚拟地址连续即可 │ │ ├── 物理页可以分散 │ │ └── 提高内存利用率 │ │ │ │ 优势 2: 内存隔离 │ │ ├── 每个进程独立的页表 │ │ ├── 硬件强制权限检查 │ │ └── 安全可靠 │ │ │ │ 优势 3: 虚拟地址空间 │ │ ├── 64 位系统支持 256TB 地址空间 │ │ ├── 只需加载需要的页面 (按需分页) │ │ └── 节省物理内存 │ └─────────────────────────────────────────────────────────────────┘
|
1.1.3 用户空间 vs 内核空间
Linux 将虚拟地址空间划分为两部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| ┌─────────────────────────────────────────────────────────────────┐ │ 64 位系统虚拟地址空间布局 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ 0xFFFFFFFFFFFFFFFF (用户空间最大地址) │ │ │ │ │ │ 用户空间 (User Space) │ │ │ ┌───────────────────────────┐ │ │ │ │ │ │ │ │ │ 程序代码、数据、堆、栈 │ │ │ │ │ 约 128TB (默认) │ │ │ │ │ │ │ │ │ └───────────────────────────┘ │ │ │ │ │ 0x00007FFFFFFFFFFF │ │ │ │ │ ────────┼──────────────── (分界线) │ │ │ │ │ 0xFFFF800000000000 │ │ │ │ │ │ 内核空间 (Kernel Space) │ │ │ ┌───────────────────────────┐ │ │ │ │ │ │ │ │ │ 内核代码、数据、结构体 │ │ │ │ │ 直接映射区、vmalloc区等 │ │ │ │ │ │ │ │ │ └───────────────────────────┘ │ │ │ │ │ 0xFFFF800000000000 │ │ │ └─────────────────────────────────────────────────────────────────┘
|
用户空间特性:
- 每个进程独立
- 使用较低的虚拟地址
- 通过系统调用访问内核
内核空间特性:
- 所有进程共享
- 使用较高的虚拟地址
- 受保护,用户无法直接访问
1.2 内存管理子系统职责
核心功能
物理内存管理
- 页面的分配、释放、回收
- 通过伙伴系统 (Buddy System) 管理物理内存
- 支持 NUMA 架构的多节点内存管理
虚拟内存管理
- 地址空间的创建、映射、保护
- 每个进程有独立的虚拟地址空间
- 实现进程间的内存隔离
页表管理
- 多级页表的创建、更新、遍历
- 实现虚拟地址到物理地址的转换 (MMU)
- TLB (Translation Lookaside Buffer) 管理
缺页处理
- 按需加载 (Demand Paging)
- 写时复制 (Copy-on-Write)
- 延迟分配策略提高内存利用率
页面回收
- LRU (Least Recently Used) 算法
- 交换 (Swap) 机制
- 在内存不足时回收页面
内存共享
1.2 内存管理架构
1.2.1 子系统组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| ┌────────────────────────────────────────────────────────────────┐ │ 内存管理子系统 │ ├────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ 页面分配器 │ │ Slab/Slub │ │ 页表管理 │ │ │ │ Buddy System│ │ Allocator │ │ Paging │ │ │ │ │ │ │ │ │ │ │ │ - 物理页面 │ │ - 小对象分配│ │ - 多级页表 │ │ │ │ - 伙伴算法 │ │ - 内核缓存 │ │ - TLB 管理 │ │ │ │ - 迁移类型 │ │ - kmalloc │ │ - 缺页处理 │ │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ 页面回收 │ │ 缺页处理 │ │ 内存映射 │ │ │ │ Page Reclaim│ │ Page Fault │ │ Memory Map │ │ │ │ │ │ │ │ │ │ │ │ - LRU 管理 │ │ - 匿名页 │ │ - mmap │ │ │ │ - kswapd │ │ - 文件页 │ │ - mprotect │ │ │ │ - 直接回收 │ │ - COW │ │ - munmap │ │ │ │ - 多代 LRU │ │ │ │ │ │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ │ │ 交换机制 │ │ 内存压缩 │ │ 内存 cgroup │ │ │ │ Swap │ │ Compaction │ │ Memcg │ │ │ │ │ │ │ │ │ │ │ │ - 交换分区 │ │ - 页面迁移 │ │ - 限制内存 │ │ │ │ - 交换缓存 │ │ - 碎片整理 │ │ - 统计使用 │ │ │ │ - zswap │ │ - kcompactd │ │ - OOM 控制 │ │ │ └──────────────┘ └──────────────┘ └─────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────┘
|
1.2.2 内存管理全景关联图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| ┌─────────────────────────────────────────────────────────────────────┐ │ Linux 6.12 内存管理全景图 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ │ │ │ 用户进程 │ │ │ │ malloc/mmap │ │ │ └──────┬───────┘ │ │ │ 系统调用 │ │ ▼ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 内核空间 │ │ │ ├──────────────────────────────────────────────────────────────┤ │ │ │ │ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ │ │ VMA管理 │────▶│ 页表管理 │────▶│ 缺页处理 │ │ │ │ │ │ mmap/munmap │ │ PGD/PUD/PMD │ │ do_anonymous │ │ │ │ │ │ (ch06,11) │ │ /PTE (ch05) │ │ _page (ch09) │ │ │ │ │ └─────────────┘ └──────┬──────┘ └──────┬──────┘ │ │ │ │ │ │ │ │ │ │ ▼ ▼ │ │ │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ │ │ 物理内存分配器 (Buddy System) │ │ │ │ │ │ free_area[order][migratetype] │ │ │ │ │ │ (ch03) │ │ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ │ │ ▲ │ │ │ │ │ │ │ │ │ ┌─────────────┐ ┌─────────────────────────────────┐ │ │ │ │ │ 页面分配 │◀────│ 页面回收 │ │ │ │ │ │ alloc_pages │ │ kswapd/direct reclaim │ │ │ │ │ │ (ch07) │ │ (ch10) │ │ │ │ │ └─────────────┘ └─────────────────────────────────┘ │ │ │ │ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ 物理内存层次结构 │ │ │ │ Node (pglist_data) → Zone → Page → Slab Object │ │ │ │ (ch02) (ch02) (ch02) (ch08) │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘
|
图例说明:
──► : 数据流向
──▲ : 反向依赖
(chXX) : 对应章节
1.3 关键源码位置
| 功能 |
目录 |
主要文件 |
| 核心内存管理 |
mm/ |
memory.c, page_alloc.c |
| 页表管理 |
mm/ |
pgtable.c, fault.c, mmap.c |
| Slab 分配器 |
mm/ |
slab.c, slub.c, slob.c |
| 页面回收 |
mm/ |
vmscan.c |
| 交换机制 |
mm/ |
swap.c, swap_state.c, swapfile.c |
| 内存压缩 |
mm/ |
compaction.c |
| 页迁移 |
mm/ |
migrate.c |
| 页缓存 |
mm/ |
filemap.c, page-io.c |
| 匿名内存 |
mm/ |
mprotect.c, mlock.c |
| 内存 cgroup |
mm/ |
memcontrol.c |
| KSM |
mm/ |
ksm.c |
| 内核页表 |
arch/*/mm/ |
pgtable.c, init.c |
| 头文件 |
include/linux/ |
mm.h, mm_types.h, mmzone.h, pgtable.h, gfp.h |
| 体系相关 |
arch/*/mm/ |
各种体系结构相关文件 |
1.4 相关数据结构概览
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| struct page; struct folio; struct zone; struct pglist_data; struct lruvec;
struct vm_area_struct; struct mm_struct; struct vm_struct;
struct ptdesc;
struct address_space;
struct mem_cgroup;
struct kmem_cache;
struct reclaim_state; struct shrinker;
struct swap_info_struct;
|