图解操作系统

本文介绍了CPU执行程序的基础知识,包括图灵机的工作原理、冯诺依曼模型下的计算机结构,详细阐述了CPU如何通过内存、总线和寄存器执行指令。还探讨了程序执行的基本过程,以及软中断的概念和在Linux系统中的处理方式。
摘要由CSDN通过智能技术生成

 

硬件结构

CPU是如何执行程序的?

图灵机的工作方式

图灵机的基本思想:用机器来模拟人们用纸笔进行数学运算的过程,还定义了由计算机的那些部分组成,程序又是如何执行的。

图灵机的基本组成如下:

  • 有一条「纸带」,纸带由一个个连续的格子组成,每个格子可以写入字符,纸带就好比内存,,而纸带上的格子的字符就好比内存中的数据或程序;
  • 有一个「读写头」,读写头可以读取纸带上任意格子的字符,也可以把字符写入到纸带的格子;
  • 读写头上有一些部件,比如存储单元、控制单元以及运算单元:1、存储单元用于存放数据;2、控制单元用于识别字符是数据还是指令,以及控制程序的流程等;3、运算单元用于执行运算指令;

以1+2为例:

  • 首先,用读写头把「1、2、+」这3个字符分别写入到纸带上的3个格子,然后读写头先停在1字符对应的格子上;
  • 接着,读写头读入1到存储设备中,这个存储设备成为图灵机的状态;
  • 然后读写头向右移动一个一个格,用同样的方式把2度如刀图灵机的状态,于是现在图灵机的状态存储着两个连续的数字,1和2;
  • 读写头在往右移动一个格,就会碰到+号,读写头读到+号后,将+号传输给控制单元,控制单元发现是一个+号而不是数字,所以没有存入到状态中,因为+号是运算符指令,作用时加和目前的状态,于是通知运算淡云工作。运算单元收到要加和状态中的值的通知后,就会吧状态中的1和2读入并计算,再将计算的结果3存放到状态中;
  • 最后,运算单元将结果返回给控制单元,控制单元将结果输给读写头,读写头向右移动,把结果3写入到纸带的格子中;
  • 通过上面的图灵机计算1+2的过程,可以发现图灵机主要功能就是读取纸带格子中的内容,然后交给控制单元识别字符是数字还是运算指令,如果是数字则存入到图灵机状态中,如果是运算符,则通知运算符单元读取状态中的数值进行计算,计算结果最终返回给读写头,读写头把结果写入到纸带的格子中。

事实上,图灵机这个看起来很简单的工作方式,和我们今天的计算机是基本一样的。接下来,我们一同再看看当今计算机的组成以及工作方式。

冯诺依曼模型

在1945年冯诺依曼和其他计算机科学家们提出了计算机具体实现的报告,其遵循了图灵机的设计,而且还提出用电子元件构造计算机,并约定了用二进制进行计算和存储。

最重要的定义是计算机基本结构分为5个部分,分别是运算器、控制器、存储器、输入设备、输出设备,这5个部分也被称为冯诺依曼模型。

存储器

控制单元  算术逻辑单元

输入 输出

运算器、控制器是在中央处理器里的,存储器就是我们常见的内存,输入设备则是计算机外界的设备,比如键盘就是输入设备,显示器就是输出设备。

存储单元和输入输出设备要与中央处理器打交道的话,离不开总线。所以,它们之间关系如图:

                寄存器                                        存储单元                输入/输出设备

控制单元                                                                      控制总线

                                                                                      数据总线

                逻辑运算单元                                                地址总线

        CPU

接下来,分别介绍内存、中央处理器、总线、输入输出设备。

内存

我们的程序和数据都是存储在内存,存储的区域是线性的。

在计算机数据存储中,数据的基本单位视字节BYTE,1字节等于8位/8bit。每一个字节都对应一个内存地址。

内存的地址是从0开始编号的,然后自增排列,最后一个地址为内存粽子结束-1,这种结构好似我们程序里的数组,所以内存的读写任何一个数据的速度都是一样的。

中央处理器

中央处理器也就是我们常见的CPU,32位和64位CPU最主要区别在于一次能计算多少字节数据:

32位CPU一次可以见4字节

64位CPU一次可以计算8字节

这里的32位和64 位,通常称为CPU的位宽。

之所以CPU要这样设计,是为了能计算更大的树枝,如果是8位的CPU,那么一次只能计算1字节0~255范围内的数值,这样就无法一次完成计算10000*500,于是为了能一次计算大数的运算

,CPU需要支持多个BYTE一起计算,所以CPU位宽越大,可以就散的数值就越大,比如说32位CPU能计算的最大整数是4294967295.

CPU 内部还有一些组件,常见的寄存器、控制单元和逻辑运算单元等。其中,控制单元丰泽控制CPU工作,逻辑运算单元负责计算,而寄存器可以分为多个种类,每种寄存器的功能又不尽相同。

CPU的寄存器主要作用是存储计算时的数据,你肯呢好奇为什么有了内存还需要寄存器?原因很简单,因为cpu离内存太远了,而寄存器就在cpu里,还紧挨着控制单元和逻辑运算单元,自然计算时速度会很快。

常见的寄存器分类:

通用寄存器,用来存放需要进行运算的数据,如需要进行加和运算的两个数据。

程序计数器,用来存储cpu要执行下一条指令「所在的内存地址」,注意不是存储了下一条要执行的指令,此时指令还在内存中,程序计数器只是存储了下一条指令的「地址」。

指令寄存器,用来存放当前正在执行的指令,也就是指令本身,指令被执行完成之前,指令都存储在这里。

总线

总线适用于CPU和内存以及其他设备之间的通信,总线可分为三种呢:

地址总线,用于指定cpu将要操作的内存地址;

数据总线,用于读写内存的数据;

控制总线,用于发送和接收信号,比如中断、设备复位等信号,CPU收到信号后自然进行相应,这是也需要控制总线;

当CPU要读写内存数据的时候一般需要通过下面这三个总线:

首先要通过地址总线来制定内存的地址;

然后通过控制总线控制是读或写命令;

最后通过数据总线来传输数据;

输入输出设备

输入设备想计算机输入数据,计算机经过计算后,把数据输出给输出设别。期间,如果输入设备是键盘,按下按键时是需要和CPU进行交互的,这时就需要用到控制总线了。

线路位宽与CPU位宽

数据是如何通过线路传输的呢?其实是通过操作电压,低电压表示0,高电压则表示1.

如果构造了高低高这样的信号,其实就是101二进制数据,十进制则表示5,如果只有一条线路,就意味着每次只能传递1bit的数据,即0或1,那么传输101这个数据就需要3次才能传输完成,这样的效率非常低。

这样一位一位传输的方式,成为串行,下一个bit必须等待上一个bit传输完成才能进行传输。当然,想一次多传输一些数据,增加线路即可,这是数据就可以并行传输。

为了避免低效率的串行传输的方式,线路的尾款最好一次就能访问到所有的内存地址。

CPU想要操作内存地址就需要地址总线:

如果地址总线只有1条,那每次只能表示0或1这两种地址,所以CPU能操作的内存地址最大数量位2个,(注意,不要理解成同时能操作2个内存地址);

如果地址总线右2条,那么能表示00、01、10、11这四种地址,所以cpu能操作的内存地址最大数量为4个。

那么想要CPU操作4G大的内存,那么就需要32条地址总线,因为2^2*2^10*2^10*2^10=2^32=4G。

知道了线路位宽的意义后,我们再来看CPU位宽。

CPU为快最好不要小雨线路位宽,比如32位CPU控制40位宽的地址总线和数据总线的话,工作起来就会非常复杂且麻烦,所以32位CPU最好和32位宽的线路搭配,因为32位CPU一次最多只能操作32位宽的地址总线和数据总线。

如果用32位CPU去加和两个64位大小的数字,就需要把这2个64位的数字分成两个低位32位数字和两位高位32位数字来计算,先加个两个低位的32位数字酸楚仅为,然后加和两位高位的32位数字,然后再加上仅为,就能计算出结果,可以发现32位CPU并不能一次性计算出加和两个64位数字的结果。

对于64位CPU就可以一次性算出加和两个64位数字的结果,因为64位CPU可以一次读如64位的数字,并且64位CPU内部的逻辑运算单元也支持64位数字的计算。但是不代表64位CPU性能比32位CPU高很多,很少应用需要算超过32位的数字,所以如果计算的数额不超过32位数字的情况下,32位和64位CPU之间没什么区别的,只有当计算超过32位数字的情况下,64位的优势才能体现出来。

另外,32位CPU最大只能操作4GB内存,就算你装了8GB内存条,也没用。而64位CPU寻址范围很大,理论最大的寻址空间位2^64即8GB。

程序执行的基本过程

冯诺依曼模型:程序实际上是一条一条指令,所以程序的运行过程就是把每一条指令一步一步的执行起来,负责执行指令的就是CPU了。

那CPU执行程序的过程如下:

第一步:CPU读取程序计数器的值,这个值是指令的内存地址,然后CPU的控制单元操作地址总线指定需要访问的内存地址,接着通知内存设备准备数据,数据准备好后通过数据总线将指令数据传给CPU,CPU收到内存传来的数据后,将这个指令数据存入指令寄存器。

第二步,程序计数器的值自增, 表示只想下一条指令。这个自增的大小,由CPU的位宽决定,比如32位的额CPU,指令时4字节,需要4个内存地址存放(一个内存地址能存一个字节的数据)因此程序计数器的值会自增4;

第三步,CPU分析指令寄存器中的指令,确定指令的类型和参数,如果是计算类型的指令,就把指令交给运算逻辑单元运算;如果是存储类型的指令,则交由控制单元执行;

简单总结一下就是,一个程序执行的时候,CPU会根据程序计数器里面的内存地址,从内存里面吧需要执行的指令读取到指令寄存器里面执行,然后根据指令长度自增,开始顺序读取下一条指令。

CPU从程序计数器去读取指令、到执行、再到下一条指令,这个过程会不断循环,直到程序执行结束,这个不断循环的过程称为cpu的指令周期。

a=1+2执行具体过程

CPU不认识a=1+2这个字符串,要把整个程序翻译成汇编语言的程序,这个过程称为编译成汇编代码。

针对汇编代码,我们还需要用汇编器翻译成机器码,这些机器码由0和1组成的机器语言,这一条条机器码就是一条条的计算机指令,这个才是CPU能够真正认识的东西。

下面来看看  a = 1 + 2 在 32 位 CPU 的执行过程:

程序编译过程中,编器器通过分析代码,发现1和2都是数据,于是程序运行时,内存会又个专门的区域来存放这些数据,这个区域就是数据段。如下图,数据1和2的区域位置:

数据1被放到0x200位置;

  • 数据 2 被存放到 0x204 位置;

注意,数据和指令是分开区域存放的,存放指令区域的地方称为正文段。

0x100:load指令:将0x200地址中的数据1装入到寄存器R0;

0x104:load指令:将0x204地址中的数据2装入到寄存器R1;

0x108:add指令:将寄存器R0和R1的数据想家,并把结果存放到寄存器R2;

0x10c:set指令/store指令:将寄存器R2中的数据存回数据段中的0x208地址中,这个地址也就是变量a内存中的地址。

编一碗好吃呢过后,具体执行程序的时候,程序计数器会被设置为0x100地址,然后依次执行这4条指令。

上面的例子中,由于是在32位CPU执行的,因此一条指令是占32位大小,所以你会发现每条指令间隔4个字节(因为内存的存储单元是1字节)。

而数据的大小是根据你在程序中指定的变量类型,比如int类型的数据则占4字节,char/byte占1字节。

指令

上面的例子中,图中指令的内容我写的是建议的汇编代码,目的是为了方便理解指令的具体内容,事实上指令的内容是遗传二进制数字的机器码,每条指令都有对应的机器码,CPU通过解析机器码老知道指令的内容。

不同的CPU有不同的指令集,也就是对应着不同的汇编语言和不同的机器码,接下来最简单的mips指集,来看看机器码是如何生成的,这样也能明白二进制的机器码的具体含义。

mips的指令是一位32位的整数,高6位代表着操作吗,表示这条指令是一条什么样的指令,剩下的26位不同指令类型锁表示的内容也就不相同,主要有三种类型R和J。

R指令:用在算数和逻辑操作,里面有读取和写入数据的寄存器地址。如果是逻辑位操作,后面还有唯一操作的位移量,而最后的功能码则是再前面的操作吗不够的时候,扩展操作吗来表示对应的具体指令的;

I指令,用在数据传输、条件分支等。这个类型的指令,就没有了唯一令的功能码,也没有了第三寄存器,而是把这三部分直接合并了一个地址值或一个常数;

J指令,用在跳转,高6位之外的26位都是一个跳转之后的地址;

接下来,我们把前面例子的这条指令:add指令将寄存器R0和R 的数据相加,并把结果放入到R2,翻译成机器码。

加和运算是、add对应的mips指令里操作码是00000,以及最末尾的功能码是10000,这些数值都是固定的,查一下mips指令集的手册就能知道的;

rs代表第一个寄存器R0的编号,即00000;

rt代表第二个寄存器R 1 的编号即00001;

rd代表目标的临时寄存器R2的编号,即00010;

因为不是唯一操作,所以位移量是00000

把上面这些数字拼在一起就是一条32位的mips'假发指令了,那么用16禁止表示的机器码则是0x00011020.编译器在编译程序的时候,会构造指令,这个过程叫做指令的编码。CPU执行程序的时候,就会解析指令,这个过程叫做指令的解码。现代大所属CPU都适用流水线的方式来执行指令,所谓的流水线就是把一个任务拆分成多个小任务,于是一条指令通常分为4个阶段,称为4级流水线,如下图:

2.2磁盘比内存慢几万倍?

2.3 如何写出让 CPU 跑得更快的代码?

2.4 CPU 缓存一致性

#2.5 CPU 是如何执行任务的?

2.6 什么是软中断?

中断是什么?

中断是一种异步的时间处理机制,可以提高系统的并发处理能力。

操作系统收到了中断请求,会打断其他进程的运行,所以中断请求的相应程序,也就是中断处理程序,要尽可能快的执行完,这样可以减少对正常进程运行调度的影响。

而且,中断处理程序在响应中断时,可能还会临时关闭中断,这意味着,如果当前中断处理程序没有执行完之前,系统中其他的中断请求都无法被响应,也就是说中断有可能丢失,所以中断处理程序要短且快。

什么是软中断?

Linux系统为了解决中断处理程序执行过长和中断丢失问题,将中断过程分成了两个阶段,分别是上半部分和下半部分。

上半部分:

用来快速处理终端,一般会暂时关闭中断请求,主要负责处理跟硬件紧密相关或时间敏感的事情。

直接处理硬件请求,也是硬中断,主要负责耗时短的工作,特点是快速执行

下半部分:

用来延迟处理上半部分未完成的工作,一般以内核线程的方式运行。

由内核触发,也是软中断,主要负责上半部未完成的工作,通常都是耗时较长的事情,他电视延迟执行

区别:硬中断是会打断CPU正在执行的任务,然后立即执行中断处理程序,而软中断是以内核线程的方式执行,并且每一个CPU都对应一个软中断内核线,名字通常为「ksoftirqd/CPU 编号」,比如 0 号 CPU 对应的软中断内核线程的名字是 ksoftirqd/0。

不过,软中断不只是包括硬件设备中断处理程序的下半部,一些内核自定义事件也属于软中断,比如内核调度等、RCU锁(内核里常用的一种锁)等。

系统里有哪些软中断?

在Linux系统里,可以通过查看/proc/softirqs的内容来看软中断的运行情况,以及/proc/interrupts的内容来知晓硬中断的运行情况。

/proc/softirqs文件的内容:

CPU0~CPU4都有自己对应不同的软中断的累计运行次数,有3点需要注意:

  • 左边白色字第一列,代表着软中断的类型,NET_RX表示网络接收中断、  NET_TX  表示网络发送中断、TIMER定时中断、RCU表示 RCU锁中断 、 SHED 表示内核调度中断。
  • 同一中断在不同CPU上累计次数是差不多的,基本在同一个数量级。
  • 这些数值是系统运行以来的累计中断次数,数值的大小没有什么参考意义,系统的中断次数的变化率才是我们要关注的,可以使用 watch -s cat /proc/softirqs命令查看中断次数的变化率。

因为软中断是以内核线程的方式执行的,可以用ps命令查看软中断内核线程:

 可以发现,内核线程的名字外面都有种括号,这说明ps无法获取他们的命令行参数, 4个ksoftirqd都代表着内核线程。那个CPU核心都对应着一个内核线程。

如何定位软中断CPU使用率过高的问题?

用top命令查看当前系统的软中断情况:

黄色部分si是CPU在软中断上的使用率,而且可以发现,每个CPU使用率都不高,两个CPU使用率虽然只有3%和4%左右,但是都用在软中断上了(其他都是0.0)。

另外,也可以看到CPU使用率最高的进程也是软中断 ksoftirqd,因此可以认为此时系统的开销主要来源于软中断。

用watch -d cat /proc/softirqs命令查看每个软中断类型的中断次数的变化率。

一般对于网络I/O比较高的web服务器,Net_RX网络接收中断的变化率相比其他中断类型快很多。

如果发现NET_RX网络接收中断次数的变化速率过快,,接下来就可以使用sar-n DEV查看网卡的网络包接收率情况,然后分析是哪个网卡有大量的网络包进来。

接着,再通过tcpdump抓包,分析这些包的来源,如果是非法的地址,可以考虑加防火墙,如果是正常流量,则要考虑硬件升级等。

总结

2.7为什么0.1+0.2不等于0.3???

 为什么负数要用补码表示?

十进制数转二进制采用的是除2取余法

int类型是32位的,最高位是符号位,剩余31位则表示二进制数据。

而负数,在计算机中是以补码的形式表示的

补码:把正数的二进制书全部取反再加1 

如果只在最高位用符号来表示负数,那么-2+1就会等于-3,如下图:

 

如果负数不是补码的方式表示,则在做基本对加减法运算的时候,还需要多一步操作来判断是否为负数,如果为负数,还得把加法反转成减法,或者把减法转成加法, 这就很不好了,毕竟加减法运算在计算机里是很常使用的,所以为了性能考虑,应该要尽量简化这个运算过程。

而用了补码的表示方式,对于负数的加减法操作,实际上是和正数加减法操作一样的。

如-2+1:

 

十进制小数怎么转成二进制?

十进制小数与二进制的转换 采用的是乘2取整法,

​​​​​​​

并不是所有小数都可以用二进制表示, 可以发现,0.1 的二进制表示是无限循环的。

由于计算机资源是有限的,所以是没办法用二进制精确的表示0.1,只能用近似值来表示,在有限的精度情况下,最大化接近0.1的二进制书,于是就会造成精度缺失的情况。

二进制小数转十进制时,小数点后面的指数幂是负数:

 

 

计算机是怎么存小数的?

1001.101二进制小数是定点数形式,代表着小数点是定死的,不能移动,如果你移动了他的小数点这个数就变了,就不再数原来的值了。

然而计算机并不是这样存储小数的,计算机存储小数的采用的是浮点数,名字里的浮点数表示小数点是可以浮动的。

比如1000.101的二进制数,可以表示成1.000101*2^3,类似数学上的科学记数法。

二进制的科学记数法要规范化,不仅要保证基数为2,还要保证小数点左侧只有1位,而且必须为

1。

000101称为位数,即小数点后面的数字;

3称为指数,指定了小数点在数据中的位置。

现在绝大多数计算机使用的浮点数,一般采用的是IEEE指定的国际标准:

符号位:表示数字是正数还是负数,为0表示整数,为1表示负数;

指数位:指定了小数点在数据中的位置,指数可以是负数,也可以是整数,指数位的长度越长则数值的表达范围就越大;比如二进制 1.0011 x 2^(-2),尾数部分就是 0011,而且尾数的长度决定了这个数的精度,因此如果要表示精度更高的小数,则就要提高尾数位的长度;

用32位表示的浮点数,称为单精度浮点数,即float变量,

用64位的浮点数,称为双精度浮点数,即double变量。

二进制小数,是如何转换成二进制浮点数的?

以10.625微粒子,看看这个数字在float里是如何存储的。

 

指数位的值=十进制数的偏移量127+移动位数3=130转成二进制数10000010

指数可能是整数,也可能是负数,指数是有符号的整数,而有符号的整数计算是比五福好麻烦的,所以为了减少不必要的麻烦,在实际存储指数的时候,需要吧指数转换成无符号整数。

float的指数部分是8位,IEEE标准规定单精度浮点的指数范围是-126~+127,于是为了把指数转换成无符号整数,就要加个偏移量,比如float的指数偏移量是127,这样指数就不会出现负数了。

 IEEE标准规定,二进制浮点数的小数点左侧只能有1位,并且还只能是1,既然这以为永远都是1,那就可以不用存起来了。于是就让23位尾数只存储小数部分,然后再计算是会自动把这个1加上,这样就可以节约1位空间,尾数就能多存一位小数,相应的精度就更高了一点。

尾数位:小数点右侧的数字, 

0.1+0.2==0.3吗?

3.1Linux内核vs Windows内核?

服务器使用的操作系统基本上都是Linux,而且内核源码也是开源的,任何人都可以下载,并增加自己的改动或功能。

内核

计算机是由各种外部硬件设备组成的,比如内存、CPU、硬盘等,如果每个应用都要和这些应建设别对接通信协议,那这样太累了,所以这个中间人就由内核来负责,让内核作为应用连接应用设备的桥梁,应用程序只需关心与内核交互,不用关心硬件细节。

内核的四个基本功能:

  • 管理进程、线程,决定哪个进程、线程使用CPU,也就是进程调度的能力。
  • 管理内存、决定内存的分配和回收,也就是内存管理的能力;
  • 管理硬件设备,为进程与设备之间提供通信能力,也就是硬件通信能力。
  • 提供系统调用,如果应用程序要运行更高权限运行的服务,那么就需要有系统调用,它是用户程序与操作系统之间的接口。

内核具有很高的权限,可以控制CPU、内存、硬盘等硬件,而应用程序具有的权限很小,因此大多数操作系统吧内存分成了两个区域:

内核空间,这个内存空间只有内核程序可以访问。

用户空间,这个内存空间专门给应用程序使用。

用户空间的代码只能访问一个局部的内存空间,而内核空间的代码可以访问所有内存空间。因此,当程序使用用户空间时,我们常说该程序在用户态执行,而程序使用内核空间时,程序则在内核态执行。

应用程序如果需要进入内核空间,就需要通过系统调用,下面来看看系统调用 的过程:

用户态:用户程序——执行系统调用——中断-内核态——执行系统调用—-中断——系统调用返回。

内核程序执行在内核态,用户程序执行在用户态。当应用程序使用系统调用时,会产生一个中断。发挥说呢个中断后,CPU会中断当前正在执行的用户程序,转而跳转到中断处理程序,也就是开始执行内核程序。内核处理完后,也就是开始执行内核程序。内核处理完后,主动触发中断,把CPU执行权限交回给应用程序,回到用户态工作。

Linux的设计

Linux的内核设计理念:

  • MultiTask,多任务
  • SMP,对称多处理
  • ELF,可执行文件链接格式
  • Monolithic Kernel,宏内核

MultiTask

MultiTask意思是多任务,代表着Linux是一个多任务的操作系统。

多任务意味着可以有多个任务同时执行,这里的同时可以是并发或并行:

对于单核CPU时,可以让每个任务执行一小段时间,时间就切换到另外一个任务,

从宏观角度看,一段时间内执行了多个任务,这被称为并发。

对于多核CPU时,多个任务可以同时被不同核心的CPU同时执行,这被称为并行。

SMP

SMP的意思是对称多处理,代表着每个CPU的地位是相等的,对资源的使用权限也是相同的,多个CPU共享同一个内存,每个CPU都可以访问完整的内存和硬件资源。

ELF

ELF的意思是可执行文件链路格式,它是Linux操作系统中可执行文件的存储格式,

ELF把文件分成了一个个分段。

另外,ELF文件有两种索引,Program header table中记录了运行时所需的段,而section header table 记录了二进制文件中各个段的首地址。

那么ELF文件是怎么生成的呢?

我们编写的代码,首先通过编译器编译成汇编代码,接着通过汇编器变成目标代码,也就是目标文件,最后通过链接器把多个目标文件以及调用的各个函数库链接起来,形成一个可执行文件,也就是ELF文件。

Monolithic Kernel

Monolithic Kernel的意思是宏内核,Linux内核架构就是宏内核,意味着Linux的内核是一个完整的可执行程序,且拥有最高的权限。

宏内核的特征是系统内核的所有模块,比如进程调度、内存管理、文件系统、设备驱动等,都在运行内核态。

不过,Linux也实现了动态加载内核模块的功能,例如大部分设备驱动是以客家在模块的形式存在的,与内核其他模块解藕,让驱动开发和驱动加载更为灵活、方便。

与宏内核相反的事微内核,微内核架构的内核只保留最基本的能力,比如进程调度、虚拟内存、中断等,把一些应用放到了用户空间,比如驱动程序、文件系统等。这样服务于服务之间是隔离的,单个服务出现故障或者完全攻击,也不会导致整个操作系统挂掉,提高了操作系统的稳定性和可靠性。

微内核功能少,可以移植性高,相比宏内核有一点不好的地方在于,由于驱动程序不在内核中,而且驱动程序一般会频繁调用底层能力,于是驱动和硬件设备交互就需要频繁切换到内核态,这样会带来性能损耗。华为的鸿蒙操作系统的内核架构就是微内核。

还有一种内核叫混合类型内核,它的架构有点像微内核,内核里面会有一个最小版本的内核,然后其他模块会在这个基础上搭建,然后实现的时候会跟宏内核类似,也就是把整个内核做成一个完整的程序,大部分服务都在内核中,这就像是宏内核的方式包裹着一个微内核。

Windows设计

当今Windows7、Windows10使用的内核叫Windows NT,NT全称叫New technology。

Windows的内核设计是混合型内核,整个内核实现的是一个完整的程序,含有非常多模块。

Windows的可执行文件的格式与Linux不同,所以这连个系统的可执行文件是不可以在对方上运行的。

Windows的可执行文件格式叫PE,称为可移植执行文件,扩展名通常是.exe、.dll、.sys等。

PE的结构:

 

总结

对于内核的架构一般有三种类型:

宏内核:包含多个模块,整个内核像一个完整的程序;

微内核:有一个最小版本的内核,一些模块和服务则由用户态管理;

混合内核:是宏内核和微内核的结合体,内核中抽象出了微内核的概念,也就是内核中会有一个小型的内核,其他模块就在这个基础上搭建,整个内核是个完整的程序。

Linux的内核设计是采用了宏内核,Windows的内核设计则是采用了混合内核。

Linux的可执行文件格式叫做ELF,Windows的可执行文件叫PE。

4.1为什么要有虚拟内存?

虚拟内存

单片机是没有操作系统的,所以每次写完代码,都需要借助工具把程序烧录进去,这样程序才能跑起来。

另外,单片机的CPU是直接操作内存的物理地址。

内存中不能同时运行两个程序,每次运行都会抹除上一次的内容。

操作系统是如何解决这个问题的呢?

这里的关键问题是这两个程序都用了绝对物理地址,这正是我们需要避免的。

我们可以把进程所使用的地址隔离开来,即让操作系统为每个进程分配独立的一套虚拟地址,人人都有,大家自己玩自己的地址就行,互不干涉,但是有个前提每个进程都不能访问物理地址,至于虚拟地址最终怎么落到物理内存里,对进程来说是透明的,操作系统已经把这些都安排的明明白白了。

操作系统会提供一种机制,将不同的虚拟地址和不同内存的物理地址映射起来。

 如果程序要访问虚拟地址的时候,由操作系统转换成不同的物理地址,这样不同的进程运行的时候,写入的是不同的物理地址,这样就不会冲突了。

于是,这里就引出了两种地址的概念:

我们程序所使用的

内存地址叫做虚拟内存地址

实际存在硬件里面的空间地址叫物理内存地址。

操作系统引入了虚拟内存,进程持有的虚拟地址会通过CPU芯片中的内存管理单元(MMU)的映射关系,来转换变成物理地址,然后再通过物理地址访问内存:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值