1. 内存管理基础:物理内存与虚拟内存、页框与页表、MMU 与 TLB、内存碎片化

在深入理解 kswapd 水位线与容器性能调优之前,必须夯实内存管理的底层知识。本章从物理与虚拟内存的抽象模型出发,逐步拆解页框、页表、MMU、TLB 以及内存碎片化等核心概念,为后续分析内存回收机制建立完整的认知框架。

1.1 物理内存与虚拟内存

物理内存是硬件提供的实际存储介质(如 DRAM),而虚拟内存是操作系统为每个进程提供的独立、连续的地址空间抽象。这种抽象通过“按需分页”机制实现,使得进程可以访问比物理内存更大的地址空间,同时实现进程间隔离。

特性 物理内存 虚拟内存
本质 硬件 RAM 芯片上的实际存储单元 操作系统提供的逻辑地址空间
大小 受硬件容量限制(如 8GB、64GB) 受 CPU 位宽限制(如 64 位可达 16EB)
连续性 物理地址可能不连续(NUMA 架构) 对进程呈现连续的线性地址空间
隔离性 所有进程共享,无保护 每个进程独立,互不干扰
映射关系 — 通过页表映射到物理页框
关键理解: 虚拟内存不是“凭空多出来的内存”,而是通过页表将虚拟页映射到物理页框或磁盘交换空间。当物理内存不足时,kswapd 会回收不活跃的物理页框,将其内容换出到磁盘,从而释放物理内存。

1.2 页框与页表

Linux 内核将物理内存划分为固定大小的块,称为页框(Page Frame),通常大小为 4KB。虚拟内存同样被划分为相同大小的虚拟页(Virtual Page)。页表(Page Table)是连接虚拟页与物理页框的映射数据结构。

页框(Page Frame)

  • 定义: 物理内存的最小管理单元,内核通过 struct page 结构体描述每个页框的状态。
  • 大小: 默认 4KB(x86_64 架构),也支持 2MB/1GB 大页(Huge Pages)。
  • 状态: 空闲、已分配(匿名页/文件页)、活跃、不活跃、脏页等。

页表(Page Table)

  • 层级结构: 现代 64 位系统使用 4 级或 5 级页表(PGD → P4D → PUD → PMD → PTE),以节省内存。
  • 页表项(PTE): 包含物理页框号(PFN)、权限位(读/写/执行)、存在位(Present)、脏位(Dirty)、访问位(Accessed)等。
  • 缺页异常: 当访问的虚拟页未映射到物理页框时,CPU 触发缺页异常,内核负责分配物理页框并建立映射。
容器场景关联: 每个容器进程拥有独立的页表。当容器内存限制(cgroup memory.max)较小时,页表本身也会占用内存(每个进程约 4-8KB 页表开销),大量短生命周期容器会导致页表内存膨胀,间接触发 kswapd 回收。
虚拟内存 → 页表 → 物理页框映射关系 虚拟地址空间 虚拟页 VP 0 虚拟页 VP 1 虚拟页 VP 2 虚拟页 VP 3 未映射(缺页) 页表(Page Table) PTE 0 → PFN 0x1A PTE 1 → PFN 0x3F PTE 2 → PFN 0x8B PTE 3 → PFN 0x2D PTE 4 → Present=0 物理页框 页框 0x1A 页框 0x3F 页框 0x8B 页框 0x2D 空闲页框 缺页异常(Page Fault):当访问未映射虚拟页时,CPU 触发异常,内核分配物理页框并更新页表

1.3 MMU 与 TLB

内存管理单元(MMU)是 CPU 内部的硬件模块,负责将虚拟地址实时转换为物理地址。每次内存访问都需要遍历页表,这个过程称为地址翻译。为了加速翻译,MMU 内部集成了TLB(Translation Lookaside Buffer),即页表缓存。

MMU 地址翻译流程

  1. CPU 发出虚拟地址(VA)。
  2. MMU 首先在 TLB 中查找是否有对应的缓存项(TLB hit)。
  3. 如果 TLB 命中,直接获得物理地址(PA),访问内存。
  4. 如果 TLB 未命中(TLB miss),MMU 遍历页表(硬件或软件方式),获取物理地址,同时更新 TLB。
  5. 如果页表项不存在(缺页),MMU 触发缺页异常,交由内核处理。
组件 位置 容量 速度 作用
TLB CPU 核内 几十~几百项 ~1 个时钟周期 缓存最近使用的页表项,加速地址翻译
页表 主存(DRAM) 随进程大小增长 几十~几百个时钟周期 存储完整的虚拟→物理映射
MMU CPU 内部 — 硬件逻辑 执行地址翻译、权限检查、缺页检测
容器性能陷阱: 在容器密集部署场景下,大量进程的页表频繁切换会导致 TLB 刷新(TLB flush),降低 TLB 命中率。使用大页(Huge Pages)可以减少页表项数量,提高 TLB 覆盖范围,显著提升内存密集型应用的性能。
MMU 地址翻译流程(含 TLB 缓存) CPU 发出虚拟地址 MMU 地址翻译 权限检查 TLB 页表缓存 命中 → 直接输出 物理地址 TLB Miss → 遍历页表 页表(内存) 多级遍历获取 PFN 物理地址 缺页异常 → 内核处理

1.4 内存碎片化

内存碎片化是长期运行系统中物理内存被分割成大量不连续小区域的现象,直接影响大块连续内存的分配成功率。碎片化分为两类:

碎片类型 定义 产生原因 典型影响
外部碎片 空闲页框分散在已分配页框之间,无法满足大块连续分配 频繁分配/释放不同大小的内存块 分配 2MB/1GB 大页失败;kswapd 频繁 compact
内部碎片 分配的内存块大于实际需求,造成浪费 固定大小页框(4KB)与可变大小请求不匹配 内存利用率降低,SLAB 分配器可缓解

Linux 内核抗碎片化机制

  • 伙伴系统(Buddy System): 将空闲页框按 2^n 阶组织,合并相邻空闲块以减少外部碎片。
  • 内存规整(Memory Compaction): kswapd 或手动触发,通过移动已分配页框来合并大块连续空闲区域。
  • 虚拟可移动区域(ZONE_MOVABLE): 将可迁移的页框集中管理,便于规整操作。
  • 大页(Huge Pages)与透明大页(THP): 减少页表项数量,降低 TLB 压力,但可能加剧内部碎片。
容器调优要点: 容器频繁创建/销毁会导致内存碎片化加剧,尤其是使用 4KB 小页时。建议在容器平台中启用 vm.compact_memory=1 定期规整,或为关键容器预留大页池(HugePages),减少碎片化对分配延迟的影响。
内存碎片化示意:外部碎片 vs 内部碎片 外部碎片 已分配 空闲 已分配 空闲 已分配 空闲 空闲块分散(40+30+60=130),但无法分配 120 连续块 内部碎片 分配 4KB(实际只用 2.5KB) 分配 4KB(实际只用 3KB) 分配 4KB 每个 4KB 页框内未使用的空间(灰色区域) 内存规整(Compaction)后 已分配页框(连续紧凑排列) 大块连续空闲区域(可分配 320 连续块) 伙伴系统合并相邻空闲块 + 内存规整移动已分配页 = 缓解外部碎片

1.5 本章小结

  • 物理内存 vs 虚拟内存: 虚拟内存提供隔离和扩展,通过页表映射到物理页框。
  • 页框与页表: 页框是物理管理单元,页表是多级映射结构,缺页异常是内核介入的入口。
  • MMU 与 TLB: MMU 硬件加速地址翻译,TLB 缓存页表项,TLB 命中率直接影响性能。
  • 内存碎片化: 外部碎片影响大块分配,内部碎片降低利用率;伙伴系统与内存规整是内核主要对抗手段。