一文让你明白CPU上下文切换

2023-05-16

我们都知道,Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉。

而在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好CPU 寄存器和程序计数器

什么是 CPU 上下文

CPU 寄存器和程序计数器就是 CPU 上下文,因为它们都是 CPU 在运行任何任务前,必须的依赖环境。

  • CPU 寄存器是 CPU 内置的容量小、但速度极快的内存。
  • 程序计数器则是用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置。

什么是 CPU 上下文切换

就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

CPU 上下文切换的类型

根据任务的不同,可以分为以下三种类型

  • 进程上下文切换
  • 线程上下文切换
  • 中断上下文切换

进程上下文切换

Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着下图中, CPU 特权等级的 Ring 0 和 Ring 3。

  • 内核空间(Ring 0)具有最高权限,可以直接访问所有资源;
  • 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。

来自极客时间

进程既可以在用户空间运行,又可以在内核空间中运行。进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。

系统调用

从用户态到内核态的转变,需要通过系统调用来完成。比如,当我们查看文件内容时,就需要多次系统调用来完成:首先调用 open() 打开文件,然后调用 read() 读取文件内容,并调用 write() 将内容写到标准输出,最后再调用 close() 关闭文件。

在这个过程中就发生了 CPU 上下文切换,整个过程是这样的:
1、保存 CPU 寄存器里原来用户态的指令位
2、为了执行内核态代码,CPU 寄存器需要更新为内核态指令的新位置。
3、跳转到内核态运行内核任务。
4、当系统调用结束后,CPU 寄存器需要恢复原来保存的用户态,然后再切换到用户空间,继续运行进程。

所以,一次系统调用的过程,其实是发生了两次 CPU 上下文切换。(用户态-内核态-用户态)

不过,需要注意的是,系统调用过程中,并不会涉及到虚拟内存等进程用户态的资源,也不会切换进程。这跟我们通常所说的进程上下文切换是不一样的:进程上下文切换,是指从一个进程切换到另一个进程运行;而系统调用过程中一直是同一个进程在运行。

所以,系统调用过程通常称为特权模式切换,而不是上下文切换。系统调用属于同进程内的 CPU 上下文切换。但实际上,系统调用过程中,CPU 的上下文切换还是无法避免的。

进程上下文切换跟系统调用又有什么区别呢

首先,进程是由内核来管理和调度的,进程的切换只能发生在内核态。所以,进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。

因此,进程的上下文切换就比系统调用时多了一步:在保存内核态资源(当前进程的内核状态和 CPU 寄存器)之前,需要先把该进程的用户态资源(虚拟内存、栈等)保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈

如下图所示,保存上下文和恢复上下文的过程并不是“免费”的,需要内核在 CPU 上运行才能完成。

来自极客时间

进程上下文切换潜在的性能问题

根据 Tsuna 的测试报告,每次上下文切换都需要几十纳秒到数微秒的 CPU 时间。这个时间还是相当可观的,特别是在进程上下文切换次数较多的情况下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。这也正是导致平均负载升高的一个重要因素。

另外,我们知道, Linux 通过 TLB(Translation Lookaside Buffer)来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB 也需要刷新,内存的访问也会随之变慢。特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。

发生进程上下文切换的场景

  1. 为了保证所有进程可以得到公平调度,CPU 时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行。
  2. 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。
  3. 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度。
  4. 当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行
  5. 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序。

线程上下文切换

线程与进程最大的区别在于:线程是调度的基本单位,而进程则是资源拥有的基本单位。说白了,所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。

所以,对于线程和进程,我们可以这么理解:

  • 当进程只有一个线程时,可以认为进程就等于线程。
  • 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的。
  • 另外,线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的。

发生线程上下文切换的场景

  1. 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。
  2. 前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据

中断上下文切换

为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。

跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等。

对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。

另外,跟进程上下文切换一样,中断上下文切换也需要消耗 CPU,切换次数过多也会耗费大量的 CPU,甚至严重降低系统的整体性能。所以,当你发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能问题。

本文整理自极客时间:《Linux性能优化实战》

PS:本文原创发布于微信公众号「不只Java」,后台回复「电子书」,说不定有你想要的经典书籍呢。公众号专注分享 Java 干货、读书笔记、成长思考。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一文让你明白CPU上下文切换 的相关文章

  • Delphi 2010-IDE 不断停止在 CPU 调试窗口

    我在 D2010 IDE 中不断出现 CPU 调试窗口 我注意到这出现在一些断点上 而其他一些断点则不会导致这种效果 无法解释这种情况到底何时发生或哪些断点导致这种情况 但似乎当调试器无法到达代码上的断点时 它会停止在方法的开始地址上 并且
  • 多核汇编语言是什么样的?

    例如 曾几何时 要编写 x86 汇编程序 您可能会收到这样的指令 将值 5 加载到 EDX 寄存器 递增 EDX 寄存器等 对于具有 4 个核心 甚至更多 的现代 CPU 在机器代码级别看起来是否只是有 4 个独立的 CPU 即只有 4 个
  • sched_getcpu() 相当于 OS X 吗?

    在 OS X 上 有没有办法找出线程正在哪个 CPU 上运行 Linux 的等效函数是调度获取CPU http man7 org linux man pages man3 sched getcpu 3 html 获取当前处理器编号 http
  • Python CPU 计数在一台 Windows 服务器上工作但在另一台服务器上不起作用?

    我编写的代码可以在 Windows XP 和 Windows Server 2008 64 位上运行 但是 我刚刚启动了 Amazon Windows 64 位实例 代码失败 非常简单 看起来像这样 import multiprocessi
  • Android:您的CPU不支持VT-x

    您的 CPU 不支持 VT x 运行此 AVD 需要 Intel HAXM 您的 CPU 不支持 VT x 不幸的是 您的计算机不支持硬件加速虚拟化 以下是您的一些选择 1 使用物理设备进行测试 2 在具有支持VT x和NX的Intel处理
  • 使用javascript检测设备CPU/GPU性能?

    这个问题并不特定于 Three js 但我会用它作为例子 我最近一直在使用 Three js 开发 Web 应用程序界面 并在 WebGL 和 Canvas 渲染器 针对桌面浏览器 之间编写了一些不错的后备程序 但现在的问题变成了如何正确检
  • Android Studio 和 Ryzen CPU?

    我知道它可能会被标记为重复 但没有一个线程对我有帮助 所以我决定自己做一个 I m a Java后端开发人员我决定学习一些 Android 的东西 几年前我在 Android Studio 工作过i5 4570处理器 然后我放弃了 现在我发
  • 执行长字传输到 CPU 需要多少个周期和大小

    该任务针对架构 ColdFire 处理器 MCF5271 我不明白执行到 CPU 的长字传输或字传输需要多少个周期以及什么大小的周期 我正在阅读图表 但不明白其中有何联系 非常感谢任何评论 我附上了两个例子和答案 数据总线大小 https
  • 尝试在 Windows PC 上禁用处理器空闲状态(C 状态)

    我需要防止处理器进入空闲状态 非C0 C状态 诚然 我对处理器 C 和 P 状态了解不多 所以请耐心等待 我们使用来自第三方供应商的相机 该相机偶尔会提供损坏的帧 供应商已确定 当 CPU 进入空闲状态时 它会干扰通过火线传输帧 为了确认这
  • 多处理和并行处理之间的比较

    有人能告诉我多处理和并行处理之间的确切区别吗 我有点困惑 感谢您的帮助 多重处理 多重处理是使用两个或多个中央处理单元 单个计算机系统中的 CPU 该术语还指 系统支持多个处理器和 或的能力 在他们之间分配任务的能力 并行处理 在计算机中
  • 哪个更快:x<<1 或 x<<10?

    我不想优化任何东西 我发誓 我只是出于好奇而想问这个问题 我知道在大多数硬件上都有位移位的汇编命令 例如shl shr 这是一个单一命令 但移位多少位 从纳秒角度或从 CPU 角度角度 是否重要 换句话说 以下任一选项在任何 CPU 上都更
  • 如何让Java使用机器上的所有CPU资源?

    我有时用 Java 编写代码 我注意到有时它在多核机器上使用超过 100 的 CPU 我现在正在一台具有 33 个 CPU 亚马逊的 EC2 的多核机器上运行一些代码 我想让我的 Java 进程使用所有可用的 CPU 这样它将具有非常高的机
  • CPU利用率和能耗之间有什么关系?

    描述 CPU 利用率和能源消耗 电 热方面 之间关系的函数是什么 我想知道它是否是线性 次线性 exp 等 我正在编写一个程序 可以降低其他程序的 CPU 利用率 负载 我主要关心的是我能在能源方面受益多少 此外 我的服务器主要用作数据中心
  • k8s hpa无法获取cpu信息[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我设置了 hpa 使用命令 sudo kubectl autoscale deployment e7 build 64 cpu perce
  • Django 开发服务器 CPU 密集型 - 如何分析?

    我注意到本地 windows7 机器上的 django 开发服务器 版本 1 1 1 正在使用大量 CPU 根据任务管理器的 python exe 条目 约为 30 即使处于空闲状态 即没有请求到来进 出 是否有一种既定的方法来分析可能造成
  • 查看x86架构中的cpu缓存内容

    如何查看或转储基于 x86 的架构的 cpu 缓存内容 每次进行缓存刷新时 我如何才能看到刷新了什么 在哪里 你不能 真的 CPU 缓存被设计为对于 CPU 上运行的代码是透明的 它具有加快代码执行速度的效果 但 CPU 管理有关缓存的所有
  • Linux:如何对系统内存施加负载?

    我正在开发一个小功能 它可以让我的用户了解 CPU 的占用情况 我在用着cat proc loadavg 它返回众所周知的 3 个数字 我的问题是 当我正在开发时 CPU 目前没有做任何事情 有没有一种好方法可以在CPU上产生一些负载 我在
  • 普通的 x86 或 AMD PC 是直接从 ROM 运行启动/BIOS 代码,还是先将其复制到 RAM? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我知道现代计算机已经修改了哈佛架构 它们可以从保存数据的地方以外的地方读取指令 这一事实是否允许它们直接从 ROM 芯片获取指令 他们是先
  • 每个 CPU 核心处于 C0 电源状态的时间

    任何帮助弄清楚如何做到这一点都会很棒 在过去一秒内 每个 CPU 核心处于 C0 电源状态的时间有多少 这是针对 Mac 应用程序的 因此需要 Objective C cocoa 和 c OS X 没有任何公开 CPU c 状态的 API
  • 将代码保存在 L1 缓存中

    我一直在阅读维基百科关于 K 编程语言的文章 http en wikipedia org wiki K programming language Performance characteristics这就是我所看到的 解释器的小尺寸和语言的

随机推荐

  • 磁盘显示设备未就绪,要怎么找到资料

    设备未就绪说明这个盘的文件系统结构损坏了 在平时如果数据不重要 xff0c 那么可以直接格式化就能用了 但是有的时候里面的数据很重要 xff0c 那么就必须先恢复出数据再格式化 具体恢复方法可以看正文了解 xff08 不格式化的恢复方法 x
  • centos7下安装vnc更改vnc默认端口号

    应用场景 xff1a 某些情景下 xff0c 需要用的linux的桌面环境 xff0c Ubuntu的桌面性能在linux发行版中算是数一数二的 xff0c 如果不熟悉Debian系统 xff0c Centos RHEL系列也行 xff1b
  • STM32-USB学习笔记(一) USB基础

    USB基础知识扫盲 前言 本文将从USB的 插入检测 身份识别 数据传输三个方面对USB通讯整个过程扫盲 xff0c 其中有些知识点的详细信息会放在文章最下面的附录中供查看 xff0c 从而保证文章的整体简洁 在进入主题之前 xff0c 首
  • VNC连接linux下vmware虚拟机win-server的分辨率设置

    最近用dell的r610装了rhel搞了几个虚拟机玩 xff0c 系统装的是2k3 xff0c 发现用3389连虚拟机的时候 xff0c 分辨率是跟本地一致的1280 1024 xff0c 用vnc连就是1024 768 xff0c 觉得奇
  • 基于maven maven-replacer-plugin 插件对JS,CSS统一加版本号

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 基于maven对JS xff0c CSS统一加版本号 在写WEB应用的时候 xff0c 每次对JS CSS文件做的修改 xff0c 对于用户来说 xff0c 都很郁闷 xf
  • 【树莓派】树莓派上刷android系统

    1 首先将下载的 andrpi3 20160626 img bz2 文件解压 xff0c 可以获得一个 IMG光盘映像文件 xff08 7G多 xff09 xff1b 2 准备1张16G TF卡 xff0c 插入电脑 xff0c 然后运行W
  • 如何应对“需求不确定型项目”?

    问题描写叙述 xff1a 需求不确定 老板直接和客户谈需求 xff0c 项目经理不能或不方便參与 xff0c 打下手 这类项目如何办 xff1f 要深层次了解客户的想法 xff0c 各种利益 xff0c 地盘等 xff0c 这非常难做得到吧
  • 利用CH341A编程器刷新BIOS,恢复BIOS,妈妈再也不用担心BIOS刷坏了

    前几天 xff0c 修电脑主析就捣鼓刷BIOS xff0c 结果刷完黑屏开不了机 xff0c 立刻意识到完了 xff0c BIOS刷错了 就从网上查资料 xff0c 各种方法试了个遍 xff0c 什么用处都没有 终于功夫不负有心人 xff0
  • STM32-串口通信(串口的接收和发送)

    文章目录 STM32的串口通信一 STM32里的串口通信二 串口的发送和接收串口发送串口接收 三 串口在STM32中的配置四 串口接收的两种实现方式1 需要更改的地方2 查询RXNE标志位3 使用中断 总结 STM32的串口通信 本文在于记
  • 技术干货|深入理解flannel

    根据官网的描述 xff0c flannel是一个专为kubernetes定制的三层网络解决方案 xff0c 主要用于解决容器的跨主机通信问题 1 概况 首先 xff0c flannel利用Kubernetes API或者etcd用于存储整个
  • Windows操作系统产品名与内部版本号的对应

    虽然Windows的命名取决于很多因素 xff0c 形式各不相同 xff0c 但是其内部版本号却是一脉相承的 xff0c 从最初的Windows 1 0到之后的Windows 2 0 Windows 3 0 xff0c 再到Windows
  • webpack + jquery + bootstrap 环境配置

    nodejs环境请自行谷歌百度 1 先安装vue cli脚手架 xff1a npm install vue cli g 2 创建项目 xff0c 此处项目名以test为例 xff1a vue init webpack simple test
  • 刚刚,OpenStack 第 19 个版本来了,附28项特性详细解读!

    刚刚 xff0c OpenStack 第 19 个版本来了 xff0c 附28项特性详细解读 xff01 OpenStack Stein版本引入了新的多云编排功能 xff0c 以及帮助实现边缘计算用例的增强功能 OpenStack由一系列相
  • Linux VNC server 安装配置

    1 安装vnc server root 64 pxe yum install tigervnc server y 2 设置 vnc server 开机启动 root 64 pxe chkconfig vncserver on 3 修改vnc
  • 常用非关系型数据库产品介绍

    1 memcache memcache xff08 键值型数据库 xff09 memcache是把访问的数据存在内存里面 xff0c 外部访问现在内存里面找 xff0c 找不到再从数据库里面找 xff0c 可以减轻数据库的压力 xff0c
  • Webpack 4.X 从入门到精通 - devServer与mode(三)

    上一篇文章里详细介绍了一下插件的用法 xff0c 这一篇文章接着丰富module exports里的属性 如今的前端发展已经非常迅速了 xff0c 伴随而来的是开发模式的转变 现在已经不再是写个静态页面并放在浏览器里打开预览一下了 在实际的
  • 块状元素与内联元素的区别

    css中块状元素是一个重要的知识点 xff0c css下height和width不起作用使我们经常遇到的问题 xff0c 这就需要我们正确区分块状元素和内联元素 块状元素和内联元素的区分很简单 xff0c 我们只需要注意html元素是否排斥
  • vsftp 锁定用户目录

    vsftp 安装以后给用户权限和锁定目录 xff1b 关闭SELinux xff1a 修改 etc selinux config文件中的SELINUX 61 34 34 为 disabled xff0c 然后重启 如果不想重启系统 xff0
  • 解决使用WinScp连接Ubantu系统失败的问题---SSH无法连接

    起因 为了互通Linux系统和Windows系统的文件 xff0c 以更好的实现文件管理和资源共享 所以在查阅资料后 xff0c 使用WinScp xff0c WinSCP是一个Windows环境下使用SSH的开源图形化SFTP客户端 它的
  • 一文让你明白CPU上下文切换

    我们都知道 xff0c Linux 是一个多任务操作系统 xff0c 它支持远大于 CPU 数量的任务同时运行 当然 xff0c 这些任务实际上并不是真的在同时运行 xff0c 而是因为系统在很短的时间内 xff0c 将 CPU 轮流分配给