系列文章目录
JAVAEE初阶第一节------计算机的工作原理
计算机的工作原理
- 计算机发展史
- 冯诺依曼体系(Von Neumann Architecture)
- CPU
- 操作系统(Operating System)
文章目录
- 系列文章目录
- 计算机的工作原理
- 一.计算机发展史
- [二. 冯诺依曼体系(Von Neumann Architecture)](#二. 冯诺依曼体系(Von Neumann Architecture))
- 三.CPU
-
- [3.1 CPU的构成(简单了解)](#3.1 CPU的构成(简单了解))
- [3. 2 CPU的基本情况](#3. 2 CPU的基本情况)
- 3.3指令(Instruction)
- [3.4 CPU 的基本工作流程](#3.4 CPU 的基本工作流程)
- [四·操作系统(Operating System)](#四·操作系统(Operating System))
-
- 4.1操作系统的定位
- [4.2 进程/任务(Process/Task)](#4.2 进程/任务(Process/Task))
-
- [4.2.1 操作系统的进程管理](#4.2.1 操作系统的进程管理)
- [4.3进程调度(Process Scheduling)](#4.3进程调度(Process Scheduling))
- [4.4进程控制块抽象(PCB Process Control Block)](#4.4进程控制块抽象(PCB Process Control Block))
-
- [4.4.1 PCB的核心属性](#4.4.1 PCB的核心属性)
- [4.4.2 支持系统对进程的调度的PCB属性](#4.4.2 支持系统对进程的调度的PCB属性)
- [4.5内存分配 ------ 内存管理(Memory Manage)](#4.5内存分配 —— 内存管理(Memory Manage))
- [4.6进程间通信(Inter Process Communication)](#4.6进程间通信(Inter Process Communication))
一.计算机发展史
计算的需求在人类的历史中是广泛存在的,发展大体经历了从一般计算工具到机械计算机到目前的电子计算机的发展历程。
人类对计算的需求,驱动我们不断的发明、改善计算机。目前这个时代是"电子计算机"的时代,发展的 潮流是:更快速、更稳定、更微型。
想要更加了解计算机发展史的话可以看看 《计算机简史》
二. 冯诺依曼体系(Von Neumann Architecture)
计算机是由软件和硬件构成的,而现代的计算机硬件, 大多遵守 冯诺依曼体系结构
- CPU中央处理器:进行算术运算和逻辑判断。(计算机中最核心的部分)
- 存储器:分为外存和内存,用于储存数据(使用二进制方式存储)。
- 内存存储空间小,外存的存储空间更大。
- 内存访问速度快,外存访问速度更慢。
- 内存的成本更高,外存的成本低。
- 内存的数据断电后会丢失,外存的数据断电后依然存在。
- 输入设备:用户给计算机发号施令的设备。(键盘,鼠标,麦克风)
- 输出设备:计算机给用户汇报结果的设备。(显示器,音箱)
对于存储空间
硬盘 > 内存 >> CPU
对于数据访问速度
CPU >> 内存 > 硬盘
计算机在CPU执行指令的时候,要经历从内存读取数据这样的操作.这就是冯诺依曼体系结构的精髓
冯诺依曼体系结构的本质是把 "执行" 和 "存储" 的操作分开。这么做主要就是为了 "解耦合" 以降低硬件设计的成本.(在那个时候是很必要的,因为当时的硬件设备不想现在这么好)
但随着硬件技术的发展,CPU越来越快了。从内存读取数据这件事就不能像以前那样显著提升计算机的速度,逐渐读取内存数据的速度就跟不上CPU的节奏了。
三.CPU
3.1 CPU的构成(简单了解)
门电路=> 半加器=>全加器=>加法器=>ALU运算器=>CPU(基本上构成)
CPU以及其他的内存硬盘等重要的设备都是由门电路构成的。
3. 2 CPU的基本情况
种类上分为:
X86 架构: intel amd --->家用PC,服务器
arm 架构: 苹果,高通 ---> 苹果电脑,智能手机
不同架构的CPU支持的指令集是不同的,对应的机器语言或汇编语言也是不同的
16位CPU, 32位CPU的汇编与64位CPU的汇编的区别:
C
int main(){
int* p = NULL;
printf("%d",sizeof(p));
return 0 ;
}
上面代码的执行结果,关键就是要看你的CPU是哪种CPU.
如果你的CPU是16位CPU,得到的结果就是2(2个字节,16个比特位)。
如果你是32位CPU,得到的结果就是4.
如果你是64位CPU,得到的就是8。
CPU的位数就和代码中内存地址用几个字节表示是密切相关的
3.3指令(Instruction)
所谓指令,即指导 CPU 进行工作的命令,主要有操作码 + 被操作数组成。
其中操作码用来表示要做什么动作,被操作数是本条指令要操作的数据,可能是内存地址,也可能是寄存器编号等。 指令本身也是一个数字,用二进制形式保存在内存的某个区域中
3.4 CPU 的基本工作流程
CPU是如何计算3 + 14 的:
假设有两个寄存器:寄存器A(0010)和寄存器B(0001)
- CPU从内存中读取到 0 地址的数据(指令)到CPU寄存器中并对这个指令进行解析(查询指令表判断这个指令要执行的操作) (前四位是指令,后四位是参数(数据))
0010 1110
0010 - 要完成的工作就是从内存中读取数据到寄存器A中
1110 - 表示内存地址 (十进制的14).说明要读取的数据在地址14上
- CPU继续从内存中读取指令并解析
0001 1111
0001 - 要完成的工作就是从内存中读取数据到寄存器B中
1111 - 表示内存地址 (十进制的15).说明要读取的数据在地址15上
- CPU继续从内存中读取指令并解析
1000 01 00
1000 - 要完成的工作就是把这两个寄存器中的数据进行相加,结果保存到第二个操作数的寄存器中
01 - 寄存器A 00 - 寄存器B
- CPU继续从内存中读取指令并解析
0100 1101
0100 - 就是把寄存器A中的数据写入到后面操作数表示的地址上(13)
1101 - 表示内存地址 (十进制的15).说明要写入的地址是地址15.
从上面的过程中,得出以下几个结论:
- CPU要执行的指令,是在内存中的(冯诺依曼体系结构,基本设定,让执行单元和存储单元解耦合)
- CPU要想执行指令,就需要先取指令,再解析指令,然后才能执行指令
- 取指令需要从内存中读取指令到CPU的寄存器中(这里没有体现出存储指令的寄存器,就只体现了AB用来计算数据的寄存器.取指令的操作,其实是非常耗时的)(读取内存操作相对于cpu执行计算,要开销大很多). 因此cpu中通过缓存,流水线等技术,来优化这里的效率
- .cpu解析指令的时候,需要用到"指令表",不同架构的CPU支持的指令表不同(x86和arm等都是不同的)指令表细节,已经写死到CPU中了,CPU是可以很容易识别的
- 指令在执行过程中,可能会带有一些操作数,不同的指令,操作数的个数含义都有所不同
- CPU重要的参数,主频。主频表示的含义,近似看成是一秒钟之内,CPU能够执行的指令个数
四·操作系统(Operating System)
4.1操作系统的定位
操作系统是一组做计算机资源管理的软件的统称。目前常见的操作系统有:Windows系列、Unix系列、 Linux系列、OSX系列、Android系列、iOS系列、鸿蒙等。
操作系统有两个基本功能(起到抽象封装的作用):
- 防止硬件被时空的应用程序滥用.(管理各种硬件设备)
- 向应用程序提供简单一致的机制来控制复杂而又通常大相径庭的低级硬件设备。(给其他软件提供稳定的运行环境)
4.2 进程/任务(Process/Task)
每个应用程序运行于现代操作系统之上时,操作系统会提供一种抽象,好像系统上只有这个程序在运行,所有的硬件资源都被这个程序在使用。这种假象是通过抽象了一个进程的概念来完成的,进程可以 说是计算机科学中最重要和最成功的概念之一。
进程是操作系统对一个正在运行的程序的一种抽象,换言之,可以把进程看做程序的一次运行过程,在电脑上正在运行的程序就可被称为是任务或者是进程.同时,在操作系统内部,进程又是操作系统进行资源分配的基本单位。(进程就是操作系统提供的一种软件资源)
4.2.1 操作系统的进程管理
- 先描述(使用类/结构体这样的方式,把实体属性给列出来)
操作系统,一般是用C/C++实现的。(没有Jva写的操作系统)因此,就可以使用结构体表示进程信息.这样的结构体就叫做PCB(进程控制块,Process Control Block)
- 再组织(使用一定的数据结构,把这些结构体/对象,串到一起)
在Linux中,使用链表这样的数据结构来把若干个task struct给串起来的
当我们看到任务管理器中的这些进程的时候,意味着系统内部就在遍历链表,并且打
印每个节点的相关信息.
如果运行一个新的程序,于是系统中就会多一个进程。多的这个进程就需要构造出一
个新的PCB,并且添加到链表上。
如果某个运行中的程序,退出了,就需要把对应进程的PCB从链表中删除掉,并且
销毁对应的PCB资源
此处的表述是一个简化版本,事实上组织方式会更复杂。
4.3进程调度(Process Scheduling)
进程,是系统分配资源的基本单位。
分时复用(并发):
- 假设一个CPU核心是一个比赛区域(CPU是包含若干区域的比赛场地),要执行的指令(进程)就是比赛选手.如果规定同一时刻一个比赛区域上只能有一个选手进行比赛(运行),这就是一个进程消耗了一个CPU资源.
可是如果比赛的选手非常多,远远超过了比赛区域的数量,那该怎么办呢?
- 假设此时的比赛区域只有一个,先让选手1,登台比赛,比赛过了一会之后,让选手1下来,选手2上.选手2比赛一段时间之后,进程3上以此类推.(即CPU核心只有一个的情况下,先执行进程1的代码.运行一段时间后让进程1结束,进程2开始执行.进程2执行一段时间后,让进程3执行...以此类推)
而由于计算机中这样切换进程的速度是非常快的(CPU频率,都是多少多少GHz,一秒钟执行几十亿条指令的)意味着,短时间内,CPU就可以进行很多次的任务切换。人也就无法感知到这个切换的过程的.因此在人眼看起来,多个任务/进程,就是"同时执行"的.(当然也有极端情况,比如,系统进程太多了,负担太重,就会出现"卡顿")
- 当比赛区域变多时,同时进行比赛的过程变得更加复杂了.这时候在同一时刻就可以有几个不同的选手在各自的比赛区域进行比赛.而不是靠快速换人的方式.(即随着CPU核心的增多,同一时刻就可以有多个不同的进程执行,而不是靠快速切换模拟的"同时执行")这种方式就称为称为"并行执行".
与之对应的,前面的并发执行,仍然存在.每个核心仍然要分时复用,仍然要快速切换.
- 当前现代的计算机执行过程,往往是并行+并发同时存在的.两个进程是并行执行还是并发执行都是看系统的调度的.(系统如何调度,取决于系统调度器模块的实现)因此,往往就把"并行"和"并发"统称为"并发".
对应的编程方式(解决一个问题,同时搞多个任务来执行,共同协作解决)就称为"并发编程"
4.4进程控制块抽象(PCB Process Control Block)
计算机内部要管理任何现实事物,都需要将其抽象成一组有关联的、互为一体的数据。在 Java 语言中, 可以通过类/对象来描述这一特征。
java
// 以下代码是 Java 代码的伪码形式,重在说明,无法直接运行
class PCB {
// 进程的唯一标识 ------ pid;
// 进程关联的程序信息,例如哪个程序,加载到内存中的区域等
// 分配给该资源使用的各个资源
// 进度调度信息(留待下面讲解)
}
这样,每一个 PCB 对象,就代表着一个实实在在运行着的程序,也就是进程。
操作系统再通过这种数据结构,例如线性表、搜索树等将 PCB 对象组织起来,方便管理时进行增删查改的操作.
4.4.1 PCB的核心属性
- PID 进程的身份标识
通过一个简单的不重复的整数来进行区分的系统会保证,同一个机器上,统一时刻,每个进程PID 都是唯一的·(后续要针对某个进程进行操作,就可以拿着PID 来进行区分了)
比如,选中某个进程,并且点击结束任务,此时,就是任务管理器获取到你选中的进程的PID,然后调用一个系统api,把PID作为参数穿进去,从而完成这里的杀死进程的操作
- 内存指针
进程运行过程中,需要消耗一些系统资源的。其中内存就是一种重要的资源
整个系统,内存这么多(16G),这16G都是可以随意使用嘛??当然不是,先从系统这里申请,系统给你分配一块,你才能使用.
每个进程都必须使用自己申请到的内存. 内存指针,就是用来描述说你这个进程,都能使用哪些内存.
一个进程跑起来的时候需要有"指令"也需要有"数据"(指令和数据,都是要加载到内存中的)
进程也需要知道,哪里是存的指令,哪里是存的数据.
- 文件描述符表
-- >描述了这个进程,所涉及的硬盘相关的资源
1)操作系统,对于硬盘这样的硬件设备,进行了封装=>文件
2)操作系统,不管你是哪种盘,都是统一进行的抽象,都是按照"文件"的方式来操作的
3)一个进程要想操作文件,需要先"打开文件"(就是让你的进程在文件描述符表中分配一个表项(构造一个结构体)表示这个文件的相关信息)
4.4.2 支持系统对进程的调度的PCB属性
1.状态
用来描述某个进程是否能够去CPU上执行,有的时候某个进程比较特殊,这时候再判断它的状态就不太方便.比如,某个进程,通过Scanner等待用户输入内容.但是用户啥时候输入就是完全不可控的事情.
因此就会有不同的状态来应对不同的问题:
(1)就绪状态:随时准备好去CPU上执行,给操作系统一打招呼就可以执行了.
(2)阻塞状态:这个进程当前不方便去CPU上执行,就不应该去调度它.(比如,进程在等待O,来自控制台的输入输出/硬盘输入输出/网卡输入输出)
例如:
java
void main(){
Scanner scanner = new Scanner(System.in);
int num = scaner.next();
}
上面代码在执行到第二条时,等待用户往控制台输入内容时,什么时候输入是不知道的.此时代码就需要暂停下来,不能继续向下走了,就是要等待用户输入一个整数.
这种进程暂停下来,不继续执行,这种等待的状态,就称为"阻塞"(这个阻塞,就是因为等待IO引起的阻塞)
- 优先级
多个进程等待系统调度,多个进程之间,调度的先后关系不是平均的,可以选择先调度哪个进程,后调度哪个,先调度谁,后调度谁都是可以调配的.比如在电脑上运行QQ的同时打开腾讯视频看视频,这个时候腾讯视频的优先级是更高的.
- 记账信息
针对每个进程, 占据了多少CPU时间,进行一个统计,并根据这个统计结果来进一步地调整不同状态的调度策略.因此就需要在下一个轮流执行的时候进行调整调度的策略.确保没有进程出现没在CPU上执行过的情况.
- 上下文
它是PCB中的数据结构相当于是在内存上的,它能支撑进程调度的重要属性,相当于文件的保存和读取.每个进程在运行的过程中,就会有很多的中间值(临时数据)在CPU的寄存器中
例如:上面CPU计算 3 + 14 的时候,CPU先使用寄存器保存3 和14 ,但是计算得出结果17后执行该指令的CPU被调度走去执行其他指令了,后面结果写入的操作还没执行.而又需要等到进程下次CPU调度回CPU的时候就可以按照之前的进度继续执行进程.
因此,就需要在进程调度出CPU之前,把当前寄存器中的这些信息单独保存到一个地方(存档)
在该进程下次再去CPU上执行的时候,再把这些寄存器的信息给恢复回来(读档)
结论:
"保存上下文":就是把CPU的关键寄存器中的数据保存的内存中(PCB的上下文属性中)
"恢复上下文": 就是把内存中的关键寄存器中的数据加载到CPU的对应寄存器中.
注意:内存指针,文件描述符表,记账信息,上下文都是数据结构,不是简单的int变量之类的
4.5内存分配 ------ 内存管理(Memory Manage)
操作系统对内存资源的分配,采用的是空间模式 (详细的暂不说明)------ 核心结论是:不同进程使用内存中的不同区域,互相之间不会干扰。(为了保证系统的稳定性,避免系统的一个进程崩溃影响到其他进程)--->"进程独立性"
4.6进程间通信(Inter Process Communication)
如上所述,进程是操作系统进行资源分配的最小单位,这意味着各个进程互相之间是无法感受到对方存 在的,这就是操作系统抽象出进程这一概念的初衷,这样便带来了进程之间互相具备"隔离性(Isolation)"。
但现代的应用,要完成一个复杂的业务需求,往往无法通过一个进程独立完成,总是需要进程和进程进 行配合地达到应用的目的,如此,进程之间就需要有进行"信息交换"的需求。进程间通信的需求就应运而生。
进程间通信,和进程的"独立性"并不冲突,系统提供一些公共的空间(多个进程都能访问到的),让两个进程借助这种公共空间来交互数据。
目前,主流操作系统提供的进程通信机制有如下:
- 管道
- 共享内存
- 文件
- 网络
- 信号量
- 信号
其中,网络是一种相对特殊的 IPC 机制,它除了支持同主机两个进程间通信,还支持同一网络内部非同一主机上的不同进程间进行通信。