当前位置:首页 > 公众号精选 > 码农的荒岛求生

你是否遇到过这样的情况:你的服务出现很高的CPU内核态使用率、磁盘IO等待时间持续偏高、可用内存持续低于工作集(Working Set)大小,线上服务开始频繁报警。。。

这时你就要警惕一种叫做缺页中断的东西。

那么,缺页中断到底是什么?

什么是缺页中断?

缺页中断是CPU访问无效内存页时触发的硬件异常。

当程序访问一个尚未映射到物理内存的虚拟地址时,CPU的内存管理单元(MMU)会检测到页表项无效(PTE invalid),随即触发缺页中断。

操作系统内核接管中断后,首先通过虚拟地址查找对应的VMA(Virtual Memory Area)区域,确认访问是否合法。若访问合法,内核会分配物理页框(pageframe),从磁盘(Swap或文件)加载所需数据,更新页表项,最后恢复程序执行。

整个过程涉及CPU、MMU和操作系统的紧密协作,是虚拟内存管理的核心机制。

那么我们该怎么对缺页中断的次数进行量化呢?

如何量化缺页中断的影响?

在Linux系统下,我们可以使用多种工具来量化分析缺页中断问题。

首先,perf stat -e page-faults工具可以帮助我们统计特定进程的缺页次数,适用于分析单个进程的内存访问模式:

   Performance counter stats for process id '6770':
            44,331      page-faults                                                 
      13.266654983 seconds time elapsed

这是一个示例,表示13s内,6770这个进程出现了44331次缺页中断。

再就是vmstat这个工具能够监控系统级的缺页速率(pgfault/s),可以用来评估系统整体性能。

如果你觉得前两个工具不够高端大气上档次,你还可以选择ftrace ,这是 Linux 内核的一个跟踪工具,主要用于性能分析和调试,它是内核自带的功能,提供对内核函数调用、系统事件以及堆栈跟踪的深入分析,常用于诊断性能瓶颈、追踪函数调用、分析内核行为等。

通过结合使用这些工具,我们可以全面了解缺页中断的发生频率、分布特征和影响因素,从而制定针对性的优化策略。

为什么高频触发缺页中断会成为性能杀手

高频缺页中断对系统性能的影响主要体现在这样几个方面。

首先,CPU占用率会显著上升,因为每次缺页中断都会触发上下文切换和中断处理,这些操作是需要消耗CPU资源的;

然后是内存访问延迟增加,特别是在涉及Swap操作时,由于需要从磁盘读取数据,以机械磁盘的性能来说访问延迟可能增加数百倍;

最后,TLB缓存失效会引发连锁反应,导致后续的内存访问都需要重新查询页表,进一步加剧性能下降。这种恶性循环会严重影响系统的整体性能,特别是在内存密集型应用中表现得尤为明显。

缺页中断的原因与解决方案

关于缺页中断的一个思维误区是认为缺页中断的唯一原因是物理内存不足。

实际上,即使有足够的内存,如果程序的内存访问模式不友好,比如随机访问大范围的内存,导致TLB未命中和缓存失效,也可能引发频繁的缺页中断。例如,遍历链表结构可能比数组更容易导致缺页,因为链表节点在内存中分散,可能分布在不同的页面上。

内存不足确实是导致缺页中断的常见原因之一,但并非唯一原因。

缺页中断的触发与内存总量、内存访问模式和操作系统行为三者密切相关。

内存不足时的缺页中断

这个场景的典型表现就是物理内存不足以容纳程序的“工作集”(频繁访问的内存页),导致操作系统频繁将内存页换出到磁盘(Swap),引发主缺页(Major Page Fault)。

解决方案也很简单粗暴直接有效,那就是扩物理内存。

再有点进取心的方案就是优化程序内存占用,使用更合理的数据解决、减少内存泄漏、避免冗余数据等等。

内存足够时的缺页中断

这个场景的典型表现就是物理内存充足,但因内存访问模式差或页表/TLB效率低,仍频繁触发次缺页(Minor Page Fault)(如访问未映射的页)或TLB未命中。

其根本原因就在于可能程序会随机访问大范围内存(如哈希表、指针跳转),导致跨页访问频繁。

又或者是未利用大页(Huge Pages),导致页表项爆炸,TLB无法高效缓存。

再一点就是多线程竞争访问不同内存区域,引发缓存行失效(Cache Line Bouncing)。

知道原因就能对症下药。

解决方案无外乎编写对程序局部性友好的程序、使用大页(Huge Pages)减少页表层级,提升TLB命中率等。

系统级行为导致的缺页

这个场景的典型表现就是即使内存充足,操作系统可能因策略(如Swappiness)主动将空闲页换出,后续访问时需换入。

针对系统级行为导致的缺页中断,我们可以采取这样几个优化措施:

  1. 调整Swappiness参数:Swappiness参数控制内核将内存页换出到Swap的倾向。通过降低该值(例如设为10),可以减少不必要的内存换出操作。

  2. 内存锁定(mlock):通过mlock()系统调用锁定关键进程的内存页,防止其被换出。该技术适用于实时性要求高的应用场景,但会降低系统内存管理的灵活性。

  3. 一把梭,禁用Swap:在物理内存绝对充足的情况下,可通过swapoff -a命令完全禁用Swap分区。该方案能够彻底避免因Swap操作导致的缺页中断,但会完全依赖物理内存,在内存不足时可能导致OOM(Out of Memory)kill。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭