4、内存子系统概览:Linux内存管理架构

内存调优,说白了就是跟数据搬家和地址翻译打交道。我做了这么多年BSP,最深的体会是:不懂内存管理,性能调优就是瞎蒙。这一章咱们把Linux内存管理的骨架搭起来,后面再聊具体怎么调。

4.1 从CPU到物理内存:MMU在中间干了什么

CPU发出的地址,其实不是直接去找物理内存的。中间有个叫MMU(Memory Management Unit)的硬件模块,它负责把虚拟地址翻译成物理地址。你想想看,如果每个进程都直接操作物理地址,那系统早就乱套了。

MMU的核心工作就三件事:

  • 地址翻译:把虚拟地址转成物理地址
  • 权限检查:判断当前操作是否合法(读/写/执行)
  • 缓存控制:管理TLB(后面会细说)

我在项目中遇到过一个问题:某款ARM芯片跑Linux,用户态程序访问一个合法的虚拟地址,结果触发段错误。查了半天,发现是MMU的页表项里权限位配错了。嗯,这种坑,硬件手册不看仔细就容易栽。

4.2 页表:虚拟地址到物理地址的映射表

页表就是一张映射表,记录着虚拟页号到物理页框号的对应关系。Linux用的是多级页表,不是一张大表。为什么?

假设32位系统,4KB页大小,虚拟地址空间4GB。如果只用一级页表,需要2^20个页表项,每个4字节,那就是4MB。每个进程一张表,100个进程就是400MB。这还不算完,很多页表项其实是空的——进程根本没用那么多内存。

多级页表就好多了。以ARM64的四级页表为例:

级别名称粒度覆盖范围
PGDPage Global Directory512GB整个地址空间
P4DPage 4th Directory1GBPGD下的子区域
PUDPage Upper Directory2MBP4D下的子区域
PMDPage Middle Directory2MBPUD下的子区域
PTEPage Table Entry4KB物理页框

只有真正用到的地址范围才会分配页表。这就是所谓的「按需分配」。我刚开始接触这个的时候也觉得绕,但画个图就清楚了。

关键点:多级页表节省内存,但代价是地址翻译变慢——每次访问内存都要查好几级表。所以TLB就派上用场了。

4.3 TLB:地址翻译的加速器

TLB(Translation Lookaside Buffer)是MMU内部的一个小容量高速缓存,专门缓存最近用过的页表项。说白了,就是地址翻译的「快照」。

TLB的工作原理很简单:

  1. CPU发出虚拟地址
  2. MMU先在TLB里找
  3. 命中:直接拿到物理地址,走人
  4. 未命中:查页表,更新TLB,再走

TLB命中率直接决定内存访问延迟。我调过一款网络处理器,TLB缺失率从5%降到1%,整机吞吐量提升了12%。你想想看,每次TLB缺失都要多走好几级页表,累积起来就是大开销。

实战技巧:TLB缺失率可以用perf stat -e dTLB-load-misses,iTLB-load-misses来监控。如果发现缺失率超过2%,就该考虑大页(HugePage)了。

4.4 物理内存与虚拟内存

这两个概念经常被混淆。我简单说清楚:

  • 物理内存:就是板子上焊的那些DDR颗粒,实实在在的硬件资源
  • 虚拟内存:每个进程看到的独立地址空间,由MMU+页表+物理内存共同实现

虚拟内存的好处很明显:

  • 进程隔离:A进程崩了不影响B进程
  • 地址空间连续:程序员不用管物理内存碎片
  • 共享内存:多个进程可以映射到同一块物理内存
  • 按需分配:用多少分配多少,不用提前占满

但虚拟内存不是免费的。每次上下文切换都要刷TLB(或者用ASID优化),页表维护也有开销。在实时性要求高的场景,这些开销必须算清楚。

我曾经在一个车载项目中,因为虚拟内存的缺页处理延迟太高,导致音频中断超时。后来改用mlock锁住关键内存页,才把问题解决。

4.5 内存碎片化:BSP工程师的噩梦

内存碎片化分两种:

类型表现原因后果
外部碎片总空闲内存够,但无法分配大块连续内存频繁分配释放,空闲页分散大块分配失败,OOM
内部碎片分配的内存块比实际需求大伙伴系统最小粒度限制内存利用率低

外部碎片是BSP工程师最头疼的。系统跑着跑着,突然分配一个16KB的缓冲区就失败了,但/proc/meminfo显示还有几百MB空闲。这就是典型的碎片化。

避坑指南:我曾经在一个视频处理项目中,连续运行72小时后,驱动申请DMA缓冲区失败。查到最后,是内核的伙伴系统无法合并出足够大的连续物理页。解决方案是:

  • 启动时预留大块内存(CMA)
  • 使用vmalloc分配非连续内存
  • 定期触发内存压缩(compact_memory)

4.6 知识体系总览

下面这张图把本章的核心逻辑串起来了。我建议你多看几遍,把每个模块的职责和关系理清楚。

Linux内存管理架构总览 CPU MMU TLB(缓存) 查表 多级页表 物理内存 碎片化问题 影响 虚拟内存 映射 说明: CPU发出虚拟地址 → MMU查TLB → 命中则直接翻译;未命中则查多级页表 → 更新TLB → 访问物理内存。 碎片化问题影响物理内存的连续分配,是BSP调优的重点关注对象。

4.7 本章小结

内存管理架构是BSP性能调优的基石。我个人的经验是:

  • 先搞清楚MMU和页表的工作原理,这是基础
  • TLB命中率是性能瓶颈的常见来源,用perf盯住它
  • 虚拟内存提供了便利,但实时场景下要小心缺页延迟
  • 碎片化问题越早预防越好,别等到系统跑崩了再查