【Linux系统】08 进程切换

目录

一、进程上下文

[1.1 硬件上下文(进程切换核心)](#1.1 硬件上下文(进程切换核心))

[1.2 软件上下文](#1.2 软件上下文)

二、触发进程切换的场景

[三、进程切换底层原理 switch_to](#三、进程切换底层原理 switch_to)

四、进程切换的开销(重点)

[进程切换 VS 同进程内线程切换对比](#进程切换 VS 同进程内线程切换对比)

[五、自愿上下文切换 & 非自愿上下文切换](#五、自愿上下文切换 & 非自愿上下文切换)

[六、查看上下文切换的 Linux 实操命令](#六、查看上下文切换的 Linux 实操命令)

[1. vmstat 全局查看系统上下文切换](#1. vmstat 全局查看系统上下文切换)

[2. pidstat 观测单个进程的上下文切换](#2. pidstat 观测单个进程的上下文切换)

七、易混淆概念辨析

[7.1 上下文切换 ≠ 系统调用](#7.1 上下文切换 ≠ 系统调用)

[7.2 进程切换发生在内核态,不能在用户态完成](#7.2 进程切换发生在内核态,不能在用户态完成)

八、面试高频问答

Q1:进程上下文包含哪些内容?

[Q2:switch_to 函数主要做了哪些工作?](#Q2:switch_to 函数主要做了哪些工作?)

Q3:进程切换开销为什么大?

Q4:自愿上下文切换和非自愿上下文切换区别?

Q5:进程切换和线程切换的核心区别?

Q6:进程切换为什么只能在内核态执行?

九、小结

一、进程上下文

进程上下文,是进程能够继续运行所需要的全部运行环境信息,分为硬件上下文 和软件上下文两大块。

1.1 硬件上下文(进程切换核心)

CPU 内部所有寄存器里面保存的数据,就是硬件上下文:通用寄存器、ebp、esp、程序计数器 PC(eip/x86_64 下 rip)、标志寄存器、段寄存器。

  • PC(程序计数器):保存下一条要执行指令的地址。
  • 当进程被从 CPU 剥离,硬件上下文会完整存入该进程 PCB(task_struct);当进程再次被调度上 CPU,从 PCB 读取硬件上下文,回填到 CPU 寄存器,进程从上次暂停的位置继续运行,不会从头执行。

参考一下Linux内核0.11代码

Linux内核调度队列

1.2 软件上下文

存放在 PCB 内,描述进程资源的软件层面信息:虚拟地址空间、页表、文件描述符表、信号状态、进程优先级、进程组、会话信息。

一句话总结:进程上下文 = 硬件现场 + 进程所有资源描述信息。

二、触发进程切换的场景

进程切换只会发生在内核态,一般在中断、系统调用返回内核态时检查是否需要调度。

  1. 时间片耗尽(最常见,非自愿切换) Linux 给就绪队列 R 状态进程分配时间片,进程在 CPU 运行,时间片用完,时钟硬件中断触发。内核进入中断处理,中断收尾阶段触发调度,换下当前进程,挑选新进程。
  2. 进程主动阻塞,自愿放弃 CPU(自愿切换) 进程调用sleep()、read()、wait()这类阻塞系统调用,需要等待 IO、等待资源。进程主动让出 CPU,状态由 R 变为 S/D,进入等待队列,触发进程切换。
  3. 抢占式调度,高优先级进程就绪 Linux2.6 引入抢占式内核。低优先级进程正在 CPU 运行,此时更高优先级进程变为就绪 R 状态,内核可以抢占 CPU,强制换下低优先级进程,运行高优先级进程。
  4. 硬件中断处理结束 硬件外设触发中断,内核进入中断处理流程。中断处理完毕,准备返回用户态之前,内核会检查是否有就绪更高优先级进程,满足条件就触发进程切换。

重要区分:中断 ≠ 进程切换。中断只是处理硬件事件;只有中断返回前调度器判定需要更换进程,才执行切换。

三、进程切换底层原理 switch_to

Linux 内核真正完成硬件上下文切换的底层函数 switch_to,是汇编函数,无法用纯 C 语言实现。C 语言执行本身依赖寄存器,一旦开始切换寄存器,C 语言栈环境失效。 函数接收两个 task_struct 指针:当前运行进程、即将要调度的下一个进程。

switch_to 内部执行完整三步:

  1. 保存当前进程硬件上下文 把 CPU 全部通用寄存器、栈寄存器、PC 指令地址,保存到当前进程 PCB 内预留的上下文存储区域。保存完成,当前进程暂停运行。
  2. 切换内核栈 + 修改 CR3 寄存器,更换页表 CR3 寄存器存放当前进程页表的物理地址,MMU 内存管理单元依靠 CR3 完成虚拟地址到物理地址的转换。 不同进程拥有独立虚拟地址空间,页表不同,修改 CR3,就切换地址空间。

进程切换和线程切换最核心差别:同一进程内线程共享一套页表,线程切换不需要修改 CR3,开销小很多。

  1. 加载新进程硬件上下文 从新进程 PCB 中读取之前保存的寄存器数据,回填到 CPU 寄存器,恢复 PC 值。CPU 从 PC 指向的地址继续执行新进程代码。

四、进程切换的开销(重点)

开销分为直接开销、间接开销,间接开销往往更大。

  1. 直接开销 寄存器保存与恢复、内核栈切换、修改 CR3 页表,也就是switch_to本身执行消耗的 CPU 周期。
  2. 间接开销(缓存失效,最大损耗) CPU L1/L2/L3 高速缓存,缓存当前进程指令与数据。当切换到另一个完全独立的进程,缓存内的数据基本失效。新进程的数据需要重新从内存加载进缓存,缓存命中率大幅下降,带来巨大性能损耗。

工程结论:大量频繁进程切换,CPU 大量时间消耗在切换本身,业务代码能拿到的 CPU 时间变少,系统吞吐量下降。

进程切换 VS 同进程内线程切换对比

表格

对比项 进程切换 同一进程内线程切换
CR3 页表寄存器 需要修改,更换独立地址空间 不修改 CR3,共享页表
CPU 高速缓存 缓存大概率失效 缓存数据大部分保留
切换开销 开销很大 开销很小

五、自愿上下文切换 & 非自愿上下文切换

使用pidstat -w命令可以观测这两类切换,是服务器性能排查核心指标。

  1. 自愿上下文切换 cswch 进程主动放弃 CPU。例如调用 sleep、等待磁盘 IO、等待管道数据,主动进入阻塞状态。属于正常现象,代表进程在等资源。
  2. 非自愿上下文切换 nvcswch 进程不是主动让出 CPU。时间片耗尽、被高优先级进程抢占,被强制剥夺 CPU。

非自愿切换数值持续很高,代表 CPU 负载压力大,就绪队列进程太多,互相争抢 CPU。

六、查看上下文切换的 Linux 实操命令

1. vmstat 全局查看系统上下文切换

复制代码
vmstat 1
  • cs列:context switch,每秒全局上下文切换次数
  • in列:每秒硬件中断次数

2. pidstat 观测单个进程的上下文切换

复制代码
pidstat -w 1
  • cswch/s:每秒自愿上下文切换次数
  • nvcswch/s:每秒非自愿上下文切换次数

七、易混淆概念辨析

7.1 上下文切换 ≠ 系统调用

系统调用:用户态陷入内核态,在内核执行内核代码。发生系统调用,不一定触发进程切换。进程依旧占用 CPU,只是从用户态切换到内核态执行代码,进程本身没有被换下 CPU。 只有调度器选择更换另一个进程,才会执行进程上下文切换。

7.2 进程切换发生在内核态,不能在用户态完成

用户态权限受限,没有权限修改 CR3 寄存器、直接操作硬件寄存器。 完整流程:

  1. 用户态运行 → 中断 / 系统调用触发,进入内核态
  2. 内核调度器选出下一个待运行进程
  3. 调用switch_to执行硬件上下文切换
  4. 新进程内核态返回自己的用户态,继续运行

八、面试高频问答

Q1:进程上下文包含哪些内容?

硬件上下文(CPU 全部寄存器、PC 指令寄存器) + 软件上下文(PCB 中保存的进程资源信息:虚拟地址空间、文件描述符、信号、优先级、进程组等),硬件上下文是切换核心。

Q2:switch_to 函数主要做了哪些工作?

汇编底层函数,保存当前进程寄存器上下文到 PCB,切换内核栈,修改 CR3 切换进程页表,加载新进程寄存器上下文,完成进程切换。

Q3:进程切换开销为什么大?

除了寄存器读写的直接开销,更换页表会导致 CPU 高速缓存失效,新进程数据需要重新从内存载入缓存,带来很大的间接性能损耗。

Q4:自愿上下文切换和非自愿上下文切换区别?

自愿:进程主动阻塞等待资源,主动放弃 CPU,属于正常 IO 等待; 非自愿:进程时间片耗尽、被高优先级进程抢占,被动被剥夺 CPU。大量非自愿切换代表 CPU 压力高。

Q5:进程切换和线程切换的核心区别?

同一个进程内部多个线程共享虚拟地址空间,线程切换不需要修改 CR3 页表,CPU 缓存大部分数据保留,切换开销远低于进程切换。

Q6:进程切换为什么只能在内核态执行?

用户态权限低,无法直接操作 CR3 页表寄存器、硬件寄存器,只有内核态拥有操作硬件的权限。进程切换一般在中断或者系统调用返回内核态时执行。

九、小结

进程切换本质:保存旧进程硬件现场,加载新进程硬件现场。底层依靠汇编switch_to完成,修改 CR3 寄存器切换页表是进程切换标志性操作。 进程切换存在性能开销,频繁切换会降低系统整体性能。学会区分自愿 / 非自愿上下文切换,是 Linux 服务器性能调优的基础。

本篇结束,下一章:环境变量

相关推荐
system_error_x1 小时前
自动化常规代码辅助系统
运维·自动化·log4j
kyle~1 小时前
Linux --- 内存管理内核子系统
linux·运维·服务器
讯捷蓝达1 小时前
戴尔 R750XS服务器不开机, 主板 Pfault fail-safe 电压异常、CPU1 VCCIO PG 电压超出范围维修
运维·服务器
昌原的儿子LEO1 小时前
嵌入式 Linux I2C 驱动开发核心知识总结:设备树与 platform 架构全解析
linux·驱动开发·架构
程序员-Benothing2 小时前
Linux内存管理详解:free、vmstat、buff/cache、swap
linux·运维·服务器
_不会dp不改名_2 小时前
leetcode_3727 最大平方交替和
linux·算法·leetcode
Lsetea2 小时前
OpenSSL报certificate revoked:error 23与CRL吊销层级排查
linux·https·ssl证书·openssl·crl
4SAPI2 小时前
多模型API调用实战:一个项目接入GPT、Claude和DeepSeek
linux·人工智能·gpt·php
j7~2 小时前
【仿 RabbitMQ 项目】发布订阅消息队列 (篇八):交换机数据管理模块,分层类设计、SQLite 回调原理与代码实现
服务器·网络·数据库·消息队列·交换机·交换机数据管理·sqlite回调原理