计算机原理探险系列(一)CPU(下)

简介: 计算机原理探险系列(一)CPU(下)

CPU上下文的切换



在理解了系统内核的调用之后,我们再来理解多个进程之间的切换:

多个进程之间的切换


通常进程的切换是需要由内核态进行控制的,所以一般进程切换过程中难免会需要进行系统的内核调用(也就是上边我所讲到的点)。


在内核态中,会有统一的机制进行这些进程的调度管理,这里面需要:

对cpu的寄存器值进行更新。


保存和更新一些进程的虚拟内存信息,栈信息等。


网络异常,图片无法展示
|


线程之间的切换


同一个进程之间的线程切换


同一个进程里虚拟内存是共享的,所以只需要更新寄存器相关的地址,在进行上下文切换的时候开销会较小一些,但是依旧难免需要进行系统的调用。


不同进程之间的线程切换

由于虚拟内存不同,所以在进行上下文切换的时候和多进程之间切换差不多。


中断上下文的切换

中断上下文切换的时候,主要发生在用户内核态,中断处理会打断进程的正常的调度和执行,被打断的进程或者线程需要暂时记录下它的上下文信息。过多的上下文切换,会把 CPU 时间消耗在寄存器、内核栈以及虚拟内存等数据的保存和恢复上,从而缩短进程真正运行的时间,导致系统的整体性能大幅下降。


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

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


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


如何分析操作系统中的cpu上下文切换情况?


vmstat指令:每隔三秒查看一次操作系统整体的上下文切换情况


vmstat 3

案例:


网络异常,图片无法展示
|


测试机器查看情况


cs(context switch)是每秒上下文切换的次数。
in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数。
复制代码


pidstat指令:查看整体的切换次数可能在实际问题排查的时候会感觉还不够用,所以这个时候可以结合pidstat指令查看每个线程的上下文切换详情。


pidstat -w
复制代码


网络异常,图片无法展示
|


自愿上下文切换(cswch)


是指进程无法获取所需资源,导致的上下文切换。比如说, I/O、内存等系统资源不足时,就会发生自愿上下文切换。


非自愿上下文切换(nvcswch)


则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换。


自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题。

非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈。


如何理解进程,线程,纤程



进程

分配资源的单位 (分配虚拟内存空间)


线程

执行程序的调度单位(不会分配任何内存空间,共享进程的内存空间)


纤程(fiber)

JVM 运行在用户空间,当它 new 一个 Thread 时,会对应在 OS 中起一个线程(内核空间,通常消耗内存大小为1m左右),所以这叫重量级线程。而纤程则是在用户态自己起一个逻辑空间,在语言层面进行调度, 和线程比起来,协程的切换不需要操作系统进行保存和恢复CPU 上下文,自己的缓存数据等,因为所有的协程都存在于同一个线程之中,所以协程的切换开销很小。一个线程包含多个纤程,又叫协程,只是协程是一个概念,而纤程是 Windows 系统对协程的一个具体实现。


Fiber在语言层面中通过用户态自己维护的栈空间来管理程序计数器,寄存信息保存等操作,不需要和os内核态打交道,这一点比线程要高效许多。


所谓市面上常说的绿色线程更多的是一个逻辑层面的概念,依赖于虚拟机来实现。操作系统对于虚拟机内部如何进行线程的切换并不清楚,从虚拟机外部来看,或者说站在操作系统的角度看,这些都是不可见的。


了解了纤程之后,我们再来看看go语言内部的设计。goroutine是Go并行设计的核心。goroutine说到底其实就是协程,但是它比线程更小,几十个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。


目前也有一些人私底下开发了些类库以支持Java语言使用fiber,但是不是特别成熟,截止到JDK13,Java对fiber的支持不是很友好,据说JDK14会较好的支持,蛮期待的。

目录
相关文章
|
存储 缓存 Java
「计算机原理」| CPU 缓存 & 缓存一致性 & 伪共享
「计算机原理」| CPU 缓存 & 缓存一致性 & 伪共享
612 0
「计算机原理」| CPU 缓存 & 缓存一致性 & 伪共享
|
算法 调度 数据中心
计算机原理探险系列(九)CPU调度机制
计算机原理探险系列(九)CPU调度机制
211 0
|
存储 缓存 安全
计算机原理探险系列(一)CPU(上)
计算机原理探险系列(一)CPU(上)
219 0
|
缓存 Android开发 芯片
ART世界探险(3) - ARM 64位CPU的架构快餐教程
我们从去年开始走入了ARM的64位时代,本文尝试用最少的知识量,让大家对ARM64-v8a有一个印象,希望篇幅控制在能够让大家在上个厕所或等个公交之类的时间看完
6057 0
|
8天前
|
存储 关系型数据库 MySQL
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
158 1
|
2月前
|
存储 关系型数据库 MySQL
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
查询服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息
111 5
|
1月前
|
C# 开发工具 Windows
C# 获取Windows系统信息以及CPU、内存和磁盘使用情况
C# 获取Windows系统信息以及CPU、内存和磁盘使用情况
39 0
|
2月前
|
Prometheus Kubernetes 监控
使用kubectl快速查看各个节点的CPU和内存占用量
在Kubernetes集群中,安装metrics-server,并使用kubectl快速查看集群中各个节点的资源使用情况。
106 0
|
3月前
|
存储 监控 Docker
如何限制docker使用的cpu,内存,存储
如何限制docker使用的cpu,内存,存储
|
3月前
|
缓存 Kubernetes 数据中心
在Docker中,如何控制容器占用系统资源(CPU,内存)的份额?
在Docker中,如何控制容器占用系统资源(CPU,内存)的份额?