Linux 内存页错误 (Page Fault) 故障排查实战 一、问题背景 内存页错误(Page Fault)是 Linux 系统中常见的内存访问异常,当进程访问的虚拟内存页不在物理内存中时触发。虽然大多数 Page Fault 是正常的(软缺页),但频繁的硬缺页会导致系统性能严重下降,甚至引发 OOM Killer 或应用崩溃。
本文通过实际案例,详细介绍 Page Fault 的排查思路、诊断工具和解决方案。
二、Page Fault 基础概念 2.1 Page Fault 类型
类型
英文
说明
性能影响
软缺页
Minor Page Fault
页已在内存中,只需更新页表
轻微
硬缺页
Major Page Fault
页不在内存中,需从磁盘加载
严重
无效缺页
Invalid Page Fault
访问非法地址,导致段错误
崩溃
2.2 常见触发场景
应用程序首次访问新分配的内存
内存交换(Swap)频繁
共享库加载
内存映射文件访问
内存泄漏导致频繁换页
三、故障现象识别 3.1 系统层面症状
输出示例:
1 2 3 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 204800 51200 32000 512000 150 300 200 100 1500 3000 25 15 55 5 0
关键字段:
si (swap in): 每秒从磁盘换入的页数,持续>100 需关注
so (swap out): 每秒换出到磁盘的页数,持续>100 需关注
3.2 进程层面症状 1 2 pidstat -p <PID> -w 1 5
输出示例:
1 2 11:00:00 PID cswch/s nvcswch/s minflt/s majflt/s Command 11:00:01 1234 150.00 12.00 500.00 50.00 java
关键字段:
minflt/s : 每秒软缺页次数
majflt/s : 每秒硬缺页次数,持续>10 需重点关注
3.3 使用 perf 深入分析 1 2 3 4 5 perf record -e page-faults -p <PID> sleep 30 perf report --stdio
四、诊断工具集 4.1 /proc 文件系统 1 2 3 4 5 cat /proc/<PID>/status | grep -E "VmSize|VmRSS|VmSwap|MinFlt|MajFlt" cat /proc/vmstat | grep -E "pgfault|pgmajfault"
4.2 sar 历史数据分析 1 2 3 4 5 sar -B 1 5 sar -B -f /var/log/sa/sa25
4.3 smem 内存分析 1 2 3 4 5 6 7 8 9 apt install smem yum install smem smem -p <PID> smem -tk
4.4 pmap 内存映射分析 1 2 3 4 5 pmap -x <PID> pmap -XX <PID>
五、实战案例 案例一:Java 应用频繁硬缺页 现象 某 Java 应用响应时间从 50ms 突增至 500ms,系统负载正常但 swap 使用率持续上升。
排查过程 1 2 pidstat -p 1234 -w 1 10
输出显示 majflt/s 持续在 80-120 之间。
1 2 cat /proc/1234/status | grep -E "VmSize|VmRSS|VmSwap"
结果:
1 2 3 VmSize: 8388608 kB # 虚拟内存 8GB VmRSS: 2097152 kB # 物理内存 2GB VmSwap: 524288 kB # 交换内存 512MB
1 2 pmap -x 1234 | tail -20
发现大量匿名内存映射被换出。
根因分析
JVM 堆内存设置过大(-Xmx6g),超出物理内存承载能力
系统其他进程占用大量内存,触发内存压力
频繁 GC 导致内存页频繁换入换出
解决方案 1 2 3 4 5 6 7 JAVA_OPTS="-Xms2g -Xmx2g -XX:+UseG1GC" sysctl vm.swappiness=10
案例二:数据库服务内存页错误 现象 MySQL 服务在高峰期间出现大量 majflt,查询延迟增加 3 倍。
排查过程 1 2 3 4 5 6 7 8 watch -n1 'grep majflt /proc/vmstat' pidstat -p $(pgrep mysqld) -w 1 mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool%';"
根因分析
innodb_buffer_pool_size 设置为 12GB,但系统总内存仅 16GB
操作系统和其他进程需要至少 4GB 内存
导致 MySQL 缓冲池频繁被换出
解决方案 1 2 3 4 [mysqld] innodb_buffer_pool_size = 8 Ginnodb_buffer_pool_instances = 8
1 2 3 echo 'vm.swappiness=1' >> /etc/sysctl.confsysctl -p
案例三:容器应用 Page Fault 爆发 现象 Kubernetes 集群中某 Pod 频繁重启,节点 dmesg 出现大量 page fault 相关日志。
排查过程 1 2 3 4 5 6 7 8 cat /proc/vmstat | grep pgkubectl describe pod <pod-name> | grep -A5 "Limits" kubectl exec <pod-name> -- cat /proc/1/status | grep -E "Vm|flt"
根因分析
容器内存 limit 设置过小(512MB)
应用实际内存需求约 800MB
触发 OOM Killer 前频繁换页
解决方案 1 2 3 4 5 6 resources: requests: memory: "512Mi" limits: memory: "1Gi"
六、预防与优化 6.1 内存配置最佳实践 1 2 3 4 5 6 7 8 9 10 11 12 echo 'vm.swappiness=10' >> /etc/sysctl.confecho 'vm.vfs_cache_pressure=50' >> /etc/sysctl.confecho 'vm.min_free_kbytes=65536' >> /etc/sysctl.confsysctl -p
6.2 应用层优化 1 2 3 4 5 6 7 8 9 void *addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); // 预触摸内存页 memset(addr, 0, size); echo 512 > /proc/sys/vm/nr_hugepages
6.3 监控告警配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 groups: - name: memory_page_fault rules: - alert: HighMajorPageFaults expr: rate(node_vmstat_pgmajfault[5m]) > 100 for: 5m labels: severity: warning annotations: summary: "高频率硬缺页" description: "节点 {{ $labels.instance }} 硬缺页率 {{ $value }} /s" - alert: ProcessMajorPageFaults expr: rate(process_majflt_total[5m]) > 50 for: 5m labels: severity: warning annotations: summary: "进程硬缺页异常" description: "进程 {{ $labels.process }} 硬缺页率 {{ $value }} /s"
七、排查流程图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 发现性能下降 ↓ 检查 vmstat si/so 指标 ↓ si/so 持续高?──否──→ 排查其他原因 ↓是 pidstat 定位高缺页进程 ↓ 分析进程内存使用 (pmap/smem) ↓ 检查应用内存配置 ↓ 调整配置/优化代码/扩容 ↓ 验证效果并持续监控
八、常用命令速查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 vmstat 1 sar -B 1 5 pidstat -p <PID> -w 1 cat /proc/meminfocat /proc/<PID>/statuspmap -x <PID> smem -p <PID> perf record -e page-faults -p <PID> perf report sar -B -f /var/log/sa/saXX
九、总结 Page Fault 故障排查的关键点:
区分软硬缺页 :硬缺页(majflt)才是性能杀手
定位问题进程 :使用 pidstat 快速定位
分析内存配置 :检查应用和系统内存设置是否合理
监控换页行为 :关注 si/so 指标变化趋势
综合优化 :结合应用配置、系统参数、硬件资源综合调整
通过本文的方法论和工具集,可以快速定位并解决大多数 Page Fault 相关的性能问题。
参考文档:
Linux Kernel Documentation: Memory Management
perf-tools GitHub Repository
Ubuntu Performance Tuning Guide