一文让你明白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上下文切换 的相关文章

  • Django 路由层 虚拟环境下建项目

    路由匹配规律 第一个参数是正则表达式 xff0c 匹配规则按照从上往下一次匹配 xff0c 匹配到一个之后立即匹配 xff0c 直接执行对应的视图函数 urlpatterns 61 url r 39 admin 39 admin site

随机推荐

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

    设备未就绪说明这个盘的文件系统结构损坏了 在平时如果数据不重要 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 轮流分配给