1. 内存管理基础:物理内存与虚拟内存的概念、MMU 的作用、页表与地址转换
在深入 OOM Killer 之前,必须牢固掌握 Linux 内存管理的三大基石:物理内存、虚拟内存以及连接二者的核心硬件——MMU(内存管理单元)。OOM Killer 的触发、评分与最终杀进程行为,都建立在这些底层机制之上。
1.1 物理内存 vs 虚拟内存
| 特性 | 物理内存 (Physical Memory) | 虚拟内存 (Virtual Memory) |
|---|---|---|
| 本质 | 硬件 RAM 芯片上的实际存储单元 | 操作系统为每个进程提供的抽象地址空间 |
| 地址空间 | 由硬件总线宽度决定(如 64 位系统最大支持 2^48 物理地址) | 每个进程拥有独立的 2^64(或 2^32)虚拟地址空间 |
| 可见性 | 所有进程共享,由内核统一管理 | 每个进程认为自己是唯一占用者,地址从 0 开始 |
| 碎片问题 | 外部碎片严重,分配大块连续内存困难 | 通过页表映射,物理上可以不连续,逻辑上连续 |
| 进程隔离 | 无天然隔离,进程 A 可直接访问进程 B 的数据 | 天然隔离,进程 A 无法访问进程 B 的虚拟地址 |
关键理解:OOM Killer 监控的是物理内存的耗尽程度。当物理内存 + Swap 被消耗殆尽,内核无法再为虚拟内存页分配物理页框时,才会触发 OOM。虚拟内存的“超额承诺”(Overcommit)机制是导致物理内存快速耗尽的直接推手。
1.2 MMU 的作用:地址转换的硬件引擎
MMU(Memory Management Unit)是 CPU 内部的一个硬件模块,负责在指令执行阶段,将 CPU 发出的虚拟地址实时转换为物理地址。没有 MMU,虚拟内存的概念将无法实现。
1.3 页表与地址转换详解
页表是 MMU 进行地址转换的“字典”。Linux 在 x86-64 架构下使用 4 级页表(PGD → PUD → PMD → PTE),将虚拟地址逐级拆解,最终找到物理页框号(PFN)。
地址转换步骤(以 4KB 页为例)
- 拆分虚拟地址:CPU 发出的 48 位虚拟地址被拆分为 5 个部分:9 位 PGD 索引、9 位 PUD 索引、9 位 PMD 索引、9 位 PTE 索引、12 位页内偏移。
- 逐级查表:MMU 从进程的 PGD 基址寄存器(CR3)开始,依次查找 PGD、PUD、PMD、PTE 四级页表项。
- 获取物理页框:最后一级 PTE 中存储了物理页框号(PFN),将 PFN 与页内偏移拼接,得到完整的物理地址。
- TLB 加速:MMU 内部有一个高速缓存 TLB(Translation Lookaside Buffer),缓存最近使用的虚拟地址到物理地址的映射,避免每次转换都走一遍 4 级页表。
性能提示:TLB 未命中(TLB Miss)是内存访问延迟的主要来源之一。大页(HugePages)通过减少页表层级和 TLB 条目数,能显著降低 TLB Miss 率,对数据库、HPC 等大内存应用至关重要。
页表项(PTE)关键标志位
| 标志位 | 含义 | 对 OOM 的影响 |
|---|---|---|
| Present (P) | 该虚拟页是否已映射到物理页框 | 若为 0,访问将触发缺页异常(Page Fault),可能引发内存分配 |
| Dirty (D) | 该物理页框内容是否被修改过 | OOM 发生时,脏页需要写回 Swap 或磁盘才能回收 |
| Accessed (A) | 该页是否被访问过 | 内核的页面回收算法(PFRA)依赖此位判断页面的活跃程度 |
| RW | 读写权限 | 写保护页(如代码段)不能被 OOM Killer 直接修改 |
1.4 虚拟内存布局与 OOM 的关联
一个典型的 Linux 进程虚拟地址空间布局如下(以 x86-64 为例):
OOM 风险区域:堆(Heap)和内存映射段(mmap)是 OOM Killer 最常“光顾”的区域。堆的无限增长(内存泄漏)或 mmap 分配大量匿名页,会快速耗尽物理内存。栈溢出通常导致段错误(Segfault),而非 OOM。
1.5 缺页异常:虚拟到物理的桥梁
当 CPU 访问一个虚拟地址,而 MMU 在页表中发现对应的 PTE 的 Present 位为 0 时,会触发缺页异常(Page Fault)。Linux 内核的缺页异常处理程序会根据情况执行不同操作:
- 有效缺页(Major/Minor Page Fault):PTE 有效但页不在内存中。内核从 Swap 分区或磁盘文件中读取数据到物理内存,然后更新页表。这是正常的内存按需加载行为。
- 写时复制(COW)缺页:PTE 的 Present 位为 1,但 RW 位为 0。内核复制物理页框并赋予写权限。这是 fork() 后父子进程共享内存的优化机制。
- 无效缺页(Segmentation Fault):PTE 完全无效(如访问未映射的地址)。内核向进程发送 SIGSEGV 信号,进程崩溃。
- OOM 触发缺页:缺页处理程序尝试分配物理页框,但此时物理内存已耗尽且 Swap 已满,分配失败。内核进入 OOM Killer 流程。
OOM 触发路径:进程访问虚拟地址 → MMU 缺页异常 → 内核缺页处理程序 → 调用
alloc_pages() 分配物理页 → 内存不足 → 调用 __alloc_pages_slowpath() → 尝试回收页面失败 → 调用 out_of_memory() → OOM Killer 选择目标进程 → 发送 SIGKILL。
1.6 本章小结
物理内存是有限的硬件资源,虚拟内存通过 MMU 和页表为每个进程提供了独立、连续、安全的地址空间。缺页异常是虚拟地址真正映射到物理页框的触发点,也是 OOM Killer 被调用的最终入口。理解这些基础概念,是后续分析 OOM Killer 评分机制、选择策略和排查内存泄漏的必备前提。