资讯动态

深入剖析 Linux 内存缺页异常:主缺页与次缺页中断对高吞吐服务的性能冲击

发布时间:2026/10/15 12:14:27 来源:尧图企业网站定制
在评估一个高吞吐微服务或高性能存储引擎的 SLA 时很多工程师常被一种诡异的“延迟毛刺Latency Spike”折磨整个系统的 CPU 利用率不到 40%网络带宽冗余充足下游数据库与 Redis 耗时极低但服务的 P99 甚至 P999 延迟却会毫无征兆地从 2ms 瞬间跳变到 500ms 以上导致调用方频繁超时甚至误触发熔断。在分布式追踪APM大盘上你只能看到某个线程在执行极其普通的业务逻辑、或者简单地读取本地文件与内存缓存时发生了停顿却抓不到任何锁竞争异常。遇到这种百思不得其解的隐蔽性能刺客如果我们把排查视角从应用层下潜到 Linux 内核的虚拟内存子系统往往会锁定一个核心底层元凶内存缺页异常Page Fault。惰性分配与缺页异常的产生机制现代操作系统为了追求内存利用率与进程启动速度的极致普遍采用虚拟内存惰性分配机制Demand Paging / Lazy Allocation。当应用在用户态调用malloc()、mmap()或者 Java 创建大对象分配堆空间时Linux 内核并不会立刻在物理内存条DRAM中划拨物理页框Page Frame。内核仅仅是在进程的虚拟内存空间task_struct-mm_struct-vm_area_struct中记录了一段虚拟地址范围。此时虚拟内存已经分配成功但在硬件 MMU内存管理单元的页表Page Table中对应的页表项PTE尚未建立有效位为 0。当进程第一次执行指令去读取或写入这块虚拟内存时CPU 的硬件 MMU 尝试将虚拟地址转换为物理地址发现该地址对应的页表项不存在。CPU 立即产生一个硬件中断异常x86-64 下的 14 号异常由硬件自动保存上下文并强制陷入内核态交由内核的通用缺页处理函数do_page_fault()进行接管。[应用进程读写虚拟地址] │ ▼ [MMU 查页表] ── 无效 / 不存在 ──► [触发 CPU 14 号中断] │ ▼ [内核 do_page_fault()] │ ┌─────────────────────┴─────────────────────┐ ▼ ▼ 【次缺页中断 (Minor Fault)】 【主缺页中断 (Major Fault)】 物理内存已存在页面 (Page Cache) 物理内存不存在需读盘 或需内核新分配空闲页并清零 (触发 Swap 换入或 mmap 文件 I/O) 耗时1 ~ 5 微秒 耗时几百微秒至数十毫秒 (D 状态)主缺页与次缺页的本质差异内核进入do_page_fault()之后根据物理内存与磁盘介质的状态缺页中断被分化为截然不同的两类1. 次缺页中断Minor Page Fault / 软缺页在以下两种典型场景下发生匿名页首次写入程序首次写入刚刚malloc或mmap的匿名内存物理内存中尚无对应页但系统拥有充足的空闲内存。内核只需要从伙伴系统Buddy System拿出一个空闲物理页将其填零并在页表中填入映射关系。共享页 / 预读缓存命中进程通过mmap读取文件虽然本进程尚未建立页表但该文件内容早已被其他进程加载到了系统的页缓存Page Cache中。内核只需建立指向现有 Page Cache 的页表映射。性能特征次缺页中断完全在 CPU 与内存总线内完成不涉及任何外设磁盘 I/O。单次耗时通常在 1 到 5 微秒。但是如果服务每秒都在大量创建、销毁几百兆的内存块每秒产生的 Minor Fault 达到数十万次频繁陷入内核态与页表锁争用mmap_lock/page_table_lock会导致系统态 CPU 利用率sys%急剧飙高整体吞吐量腰斩。2. 主缺页中断Major Page Fault / 硬缺页主缺页则是高吞吐系统的“性能灾难”。它意味着进程访问的数据不仅在当前进程页表中没有映射而且在整机的物理内存中根本不存在典型场景Swap 交换区换入系统内存紧张内核kswapd守护进程将该进程长时间不访问的内存页换出Swap Out到了磁盘的 Swap 分区。当进程突然重新访问这部分数据时内核必须发起同步磁盘 I/O将数据从 Swap 分区读回内存。冷文件 mmap 读取进程使用mmap映射了一个数十 GB 的大型数据文件如 RocketMQ CommitLog 或 RocksDB SST 文件首次顺序或随机读取某个未预读的块。性能特征主缺页中断强依赖底层存储介质的物理 I/O 读取。如果在机械硬盘HDD上一次随机读需要 10ms 左右的寻道时间即便在极速的 NVMe SSD 上加上内核 I/O 调度与排队也需要 100 微秒至数毫秒。在此期间发起调用的线程会被内核强制修改状态为不可中断睡眠TASK_UNINTERRUPTIBLE即ps看到的D状态彻底让出 CPU 挂起等待磁盘响应。如果一个批处理请求触发了连续几十次主缺页线程直接卡死几百毫秒P99 延迟应声崩盘。生产排查实战如何精准抓取缺页风暴当服务出现长尾延迟抖动时不要盲目去查业务代码使用以下三个维度的 Linux 观测工具迅速定位。1. 监控系统级缺页频率sar -B使用sysstat工具包的sar -B命令查看整机每秒的缺页统计# 每隔 1 秒输出一次内存分页统计 sar -B 1输出片段分析09:15:01 AM pgpgin/s pgpgout/s fault/s majflt/s pgfree/s 09:15:02 AM 0.00 0.00 12480.00 0.00 28900.00 09:15:03 AM 34890.00 0.00 89410.00 245.00 12000.00 -- 警报fault/s每秒发生的缺页中断总数主缺页 次缺页。majflt/s每秒发生的主缺页中断次数。正常高吞吐在线服务该值应严格稳定在 0 附近。如果突然出现几百上千次majflt/s且伴随pgpgin/s飙升说明服务正在疯狂从磁盘/Swap 同步读页。2. 针对指定进程追踪累计与瞬时缺页使用ps查看目标进程自启动以来的累计主次缺页数# 查看进程的 Minor Faults (min_flt) 和 Major Faults (maj_flt) ps -o pid,comm,min_flt,maj_flt -p PID使用/proc/PID/stat实时采样计算增量字段 10minflt和字段 12majflt记录了该进程用户态触发的缺页总数。3. 用 perf 定位触发缺页的业务调用栈如果确认缺页严重可以使用 Linuxperf工具直接抓取导致缺页中断的代码堆栈# 采样记录触发 page-faults 的调用栈持续 10 秒 perf record -e page-faults -g -p PID -- sleep 10 # 解析并查看调用火焰图或报告 perf report --stdio -n --no-children你会在输出中清晰地看到到底是哪个类、哪个函数在申请大数组或调用mmap时在内核__handle_mm_fault处耗尽了时间。高吞吐服务的主干优化策略在构建核心交易与高并发存储引擎时针对缺页异常我们必须采取防御性工程措施1. 生产环境彻底关闭 Swap或者极致调低 swappiness很多线上集群的性能毛刺都是因为系统还有几 GB 空闲内存但内核却因为vm.swappiness60默认配置悄悄把 Java 堆内存或 Go 运行时内存 Swap 到了磁盘。在容器化或专属计算节点中果断执行# 彻底关闭系统 Swap swapoff -a # 内核参数禁用激进换出 sysctl -w vm.swappiness02. 内存预分配与内存预热Pre-Touch对于 JVM 应用设置了-Xms16g -Xmx16g并不意味着物理内存已经被分配了 16G如果不进行预热服务刚上线承接大流量时前几十秒会因为不断触发次缺页中断导致大量 CPU 损耗与卡顿。必须在 JVM 启动参数中开启# 在 JVM 启动时强制逐页写入初始字节触发所有次缺页中断在上线前完成物理内存绑定 -XX:AlwaysPreTouch对于 C / Go 自研引擎在通过mmap分配大内存池后主动通过循环对每个 Page4KB 步进写一个字节或者调用madvise(addr, length, MADV_WILLNEED)提示内核提前进行物理预读。3. 使用 mlock 锁定内存不被换出对于底层延迟要求达到亚毫秒级Sub-millisecond的核心网络或交易程序调用系统调用mlock()或mlockall(MCL_CURRENT | MCL_FUTURE)强行将虚拟地址空间锁在物理 RAM 中内核绝对不会将其换出到磁盘从根源上杜绝主缺页中断的发生。4. 警惕透明大页THP的后台整理锁竞争虽然 2MB / 1GB 的大页Huge Pages可以大幅减少页表项数量与 TLB 缺失率但 Linux 的**透明大页Transparent Huge Pages, THP**在高并发动态内存分配下其后台khugepaged线程进行内存碎片整理Compaction时会长时间持有全局内存读写信号量反而会导致缺页中断的处理时间暴增数十倍。业界最佳实践对于 Redis、Kafka、MySQL 等数据库与消息中间件一律显式禁用透明大页改为madvise或使用静态配置的 HugeTLB。# 禁用透明大页 echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag从表层的业务响应时间到底层的缺页中断与物理页分配只有打通了操作系统内存管理的这根任督二脉高吞吐服务的性能调优才不会沦为“盲人摸象”。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑