引导程序:当计算机开机运行时,需要运行一个初始程序,位于计算机的固件,如只读内存ROM,将操作系用内核加载到内存中,除了内核外,一些服务也会在启动时加到内存成为系统程序或后台,一旦完成,系统完全启动,等待事件发生(如触发一个软件)
中断:事件发生通常通过硬件或软件的中断来通知,硬件可以通过系统总线发送信号到CPU,以触发中断,软件可以通过执行系统调用(systemcall)触发中断
存储结构
内存,即随机访问内存RAM,或动态随机访问内存(不一定连续),DRAM
只读内存,ROM,数据不可修改,不可写。
内存有易失性
外存:非易失性,数据可持久化
寄存器->高速缓存->内存->固态磁盘->硬盘->光盘->磁盘
I/O结构
pass
从处理器数量分类:
-
单处理器系统:执行一个通用指令集,该指令集包括执行用户进程的指令,而专用处理器执行有限的指令集
-
多处理器系统:多核系统,集成多个计算机到单个芯片的系统
内存->CPU*n(寄存器,高速缓存)
(一个芯片上)多处理器系统的特点:增加吞吐量,规模经济(对于生产商而言),增加可靠性
非对称性处理器:一个主处理器控制系统,其他处理器或向主处理器要任务或处理预先规定的任务,成为主从关系,主处理器调度从处理器,安排任务
对称处理器:每个处理器都参与完成操作系统的所有任务,没有主从关系
- 集群系统:系统将多个CPU组合在一起,一般通过网络链接,提供高可用性的服务
操作系统的执行
多道程序能力:单个程序不能让CPU和IO设备始终忙碌,多道程序通过安排作业,使得CPU总有一个执行作业,从而提高CPU利用率。
解释下多道程序:批处理系统下有多个作业,双击qq会先放到磁盘里面一个叫做作业池的地方,准备执行,加载程序时,将作业池拿到内存里开始运行,在内存里,这些作业叫做进程(执行中的程序),就是把硬盘中的二进制文件加载到了内存中,CPU来切换执行多个进程(因为CPU的速度非常快,但一次只能执行一条指令,有大量时间空闲,这样做可以提高CPU利用率)
为什么先要保存到磁盘的作业池?
内存太小不能容纳所有作业,所有作业首先保存到磁盘的作业池,
分时系统:是多道程序设计的自然延伸,对于分时系统,CPU通过切换作业执行多个作业,由于切换频率很高,用户可以在程序运行时与其交互。分时需要确保响应时间。
解释伪并行的本质:CPU执行每个作业一个时间片,但因为切换上下文的非常快,几乎感受不出来,以至于认为是并行
双重模式与多重模式的执行
操作系统是中断驱动的,事件是由中断或陷阱/异常引起的,陷阱是一种软件生成的中断,或源于出错,源于用户程序的特定请求
为确保os的正确运行,必须区分操作系统代码和用户代码的执行
- 用户模式和内核模式
计算机硬件可以通过模式为来表示当前模式:内核模式0和用户模式1
当计算机系统执行用户应用时,系统处于用户模式,当用户应用通过系统调用,请求操作系统服务时,系统必须从用户模式切换到内核模式
解释系统调用:用户想要调用硬件,OS提供一些接口(API,对外提供服务)
解释用户模式到内核模式的调用:用户进程执行->调用系统调用(触发陷阱,陷阱模式位设置位0,执行系统调用)->执行系统调用(内核模式)->(返回模式位=1)->从系统调用返回(用户模式),切换的过程耗时,浪费性能,尽量减少用户模式到内核模式的切换
为什么需要系统调用?
双重模式执行提供保护手段,以便防止操作系统和用户程序收到错误用户程序的影响,这种防护实现为,将可能引起损害的机器指令作为特权指令,并且硬件只有在内核模式下才允许执行特权指令,如果在用户模式下试图执行特权指令(直接调用硬件),那么硬件并不执行该指令,而是认为该指令非法,并将以陷阱形式通知操作系统
定时器设置的意义?
操作系统应该维持控制CPU,防止用户程序陷入死循环,或者不调用系统服务并且不将控制返回给操作系统,为了实现这一目标可以使用定时器,设定为指定周期后中断计算机。
进程管理
在未被CPU执行之前,程序做不了任何事情,执行中的程序称为而进程,因为程序是被动实体,只有加载到内存中,成为进程才是主动实体
单线程进程有一个程序计数器,指定了下一个所要执行的指令
进程是系统的工作单元,系统由多个进程组成,其中由操作系统进程,也有用户进程,所有进程并发执行
为什么需要内存管理?
为了改进CPU的利用率和用户的计算机响应速度,计算机应在内存中保留多个程序,这就需要内存管理。
操作系统负责内存管理的以下活动
- 记录内存的哪部分被使用以及谁在使用
- 决定哪些进程会调入调出内存
- 根据需要分配和释放内存空间
高速缓存
为什么需要高速缓存?高速缓存一般集成在CPU中,比起重新去内存中调用,速度更快
高速缓存的大致原理?在去内存取数据之前,会先到高速缓存中看一下有没有数据,如果没有,去内存中取,放到高速缓存中一份,再拿到CPU中
高速缓存的数据一致性问题?如果内存中数据改变,必须保证高速缓存中对应数据失效,否则不一致
多级高速缓存?一级缓存最靠近CPU,最快最小
例:整数A从磁盘到寄存器的迁移:硬盘->内存->高速缓存->硬件寄存器
I/O系统
I/O子系统为操作系统本身隐藏了IO设备的特性
IO子系统包括以下几个组件:缓冲,高速缓存的内存管理组件;USB;硬件驱动程序
只有设备驱动程序才知道控制设备的特性
计算环境
传统计算
移动计算:只能手机或平板电脑的计算
分布计算:分布式系统是物理上分开的,通过网络相连的一组计算机系统
客户机-服务器计算
对等计算:不区分客户机和服务器
云计算:虚拟化技术的延伸
虚拟化
通过虚拟化,操作系统可以在其他操作系统上运行应用程序
无虚拟化:进程->内核->硬件
虚拟化:进程->内核->VM->虚拟机管理器->硬件
操作系统的服务
用户和其他系统程序->用户界面->系统调用->服务->操作系统->硬件
用户界面:GUI和命令解释程序,即shell,将用户输入的命令转换为机器指令,占用资源更少
系统调用
系统调用提供操作系统服务接口,这些调用通常以高级语言编写or汇编?
例:一个简单的复制文件的操作(获取输入文件名称,写提示到屏幕,接受输入,获取输出文件名称,写提示到屏幕,接受输入,打开输入文件,如果不存在,终止,创建输出文件,如果存在,终止,循环,读取输入文件,写到输出文件,直到读取失败,关闭输出文件,写完成消息到屏幕,正常终止)
用户应用程序(如C++,C)使用open()调用系统调用接口,切换到内核模式,底层硬件实行
系统调用的类型:进程控制,文件管理,设备管理,信息维护,通信和保护
进程控制
如果一个系统调用异常或暂停当前执行的程序,会存储内存到磁盘,并生成错误信息
锁的意义?
多进程中,多个进程会共享数据,为了确保共享数据的完整性 ,操作系统通常提供系统调用->允许一个进程锁定共享数据,这样在结束前,其他进程不能访问该数据
例:MS-DOX
可用内存->进程->命令解释程序->内核
操作系统的结构
封装子系统模块
采用为内核技术的具体实现和好处?
对内核进行模块化,把不必要的部件从内核中移除,将他们当作系统级和用户级的程序来实现,结果是内核较小
微内核的主要功能是,为客户端程序和运行在用户空间中的各种服务提供通信
优点:便于移植和拓展(部件)
缺点:增加模式切换,增加系统功能开销
目前操作系统采用可加载的内核模块:需要哪些就加载哪些(比如调度类,文件系统,设备和总线驱动程序)
进程管理
现代操作系统允许加载多个程序到内存,以便并发执行,进程即执行中的程序,进程是现代分时操作系统的工作单元
并发执行:通过在进程之间切换CPU
当一个可执行文件被加载到内存时,这个程序就成为进程,进程时执行中的程序实体,相同一份代码可以有多个程序实体(进程),进程是操作系统进行资源分配和调度的基本单位
但是,进程不只是程序代码,进程还包括当前活动,PC的值和寄存器的内容
进程状态
就绪 运行 等待
进程状态图
pass
进程控制块(PCB)包含许多某个特定进程相关信息,包括新城状态,程序计数器(下一个指令地址),CPU寄存器,CPU调度信息…….本质就是保存上下文信息
进程键CPU切换
执行->中断->保存状态到PCB1->从PCB1重新加载状态->执行->中断->保存转台到PCB1->从PCB1更新加载状态->执行
单线程:每个进程一次只能执行一个任务
- 进程调度
表示进程调度的队列图
pass
操作系统通过调度程序来选择进程而后执行进程
- 长期调度程序:如批处理系统,将进程保存到类似磁盘的大容量存储设备
- 短期调度程序:从内存中准备执行的进程中许纳泽进程,并分配CPU执行
- 中期调度程序:将进程从内存(或CPU竞争中)移除,从而降低多道程序调度,之后进程可以被重新载入内存,并从中断处继续执行,称之为交换(换出,换入)
IO密集型:执行进程时,IO占用更多的时间,可能要等待IO
CPU密集型:执行进程时,CPU计算占用更多时间
上下文切换:
pass
进程运行
并行与并发区别?单核上并发:CPU上下切换(策略),毕竟单CPU一个时间只能执行一个进程。并行:多核,执行多个进程
sleep()放弃执行,但CPU此时选择其他进程不一定切换一个不一样的
- 多线程模型
用户线程
内核线程
- 多对一模型
为什么不用多对一模型?容易阻塞(一个线程阻塞影响所有)不允许运行在多处理器上
- 一对一模型
支持并发,但是开销影响性能
- 多对多模型
多对并发,相对于多对一模型,阻塞时允许调用另一个线程
- 双层模型
线程池优点?
进程调度
CPU是如何选择进程的?
单处理器:
多道程序
当一个进程等待时,交出CPU
进程包括CPU执行和IO等待,两者交替
IO密集型&CPU密集型
抢占调度
等待状态和就绪状态?等待状态缺少IO和CPU,就绪就只缺少CPU
抢占型和非抢占型
调度程序
比较CPU调度算法准则:CPU使用率,吞吐量,周转时间,等待时间,响应时间
最大化CPU使用率和吞吐量,最小化周转时间,等待时间和响应时间
抢占式内核
非抢占式内核
调度算法
先到先服务FCFS
使用队列FIFO实现,当一个进程进入队列时,它的PCB会被连接到队列尾部,当CPU空闲时,它会分配给头部的进程
非抢占式,平均等待时间比较长
最短作业优先调度
SJF(shortest-job-first)
优点:平均等待时间最小,性能最好
QA:如何知道下次CPU执行系列?
对于批处理系统的长期调度,…
对于短期CPU调度,…
可以是抢占式或非抢占式,依据到达时间,执行时间(delta即为剩余时间)
抢占SJF调度称为最短剩余时间优先调度
优先级调度
每个进程都有一个优先级关联,具有最高优先级的进程会分配到CPU,先攻优先级的进程按FCFS.SJF算法优先级位下次CPU执行的倒数,CPU执行越长,优先级越小
但并不是优先级数值越小,优先级越高!(可能是越大)
- 主要问题:无穷堵塞/饥饿问题
解决方法:老化:增加在系统中等待很长时间的进程的优先级
轮转调度
RR
专门位分时系统设计,增加了抢占时间片切换进程,每个进程分配不超过一个时间片的CPU执行
抢占,性能取决于时间片大小,如果时间片很大,类似于FCFS(实际进程执行小于时间片),如果时间片很小,导致频繁的上下文切换(性能消耗)
多级队列调度
根据属性,将一个进程永久放到一个队列
优先级高的队列先执行,可能会有饥饿问题
多级反馈调度
允许进程在队列之间切换,阻止饥饿发生
- 为什么将IO密集型放在更高优先级队列而不是CPU密集型?
因为IO密集型比较耗时,CPU比较空闲,根据反馈调度,CPU更有时间去执行优先级较低的
多处理器调度
之前讨论的都是单处理器
非对称处理器:一个处理器处理所有调度决定,IO处理等系统活动,其他处理器只执行用户代码,简单,减少数据共享需要
多对称处理器SMP:每个处理器自我调度,都有私有就绪进程队列
处理器亲和性:试图让一个进程运行在一个处理器上
- 如果进程转移到其他处理器会发生什么?
一个处理器缓存无效,第二个重新填充
负载平衡:尽量将所有负载平衡分配到SMP每个处理器上,两种方法:推迁移和拉迁移,两种并行实现,但会抵消处理器亲和性的好处
实时CPU调度
软实时和硬实时系统,硬实时系统必须保证以恶搞任务再它的戒指期限之前完成
实时操作系统与一般的操作系统相比,最大的特色就是“实时性”,如果有一个任务需要执行,实时操作系统会马上(在较短时间内)执行该任务,不会有较长的延时。这种特性保证了各个任务的及时执行。
最小化延迟
中断延时:先完成正在执行的指令,再确定中断类型(IOor时间片没?),保存当前进程状态,采用特定的中断服务程序(ISR),上下文切换,这些总时间是中断延迟
调度延时:从停止一个进程到启动另一个进程所需的时间量
!尽量减少中断延迟,确保实时任务得到尽快处理
- 如何减少调度延迟?
提供抢占式内核
- 调度延迟的冲突部分
优先权调度
进程周期性,定期需要CPU,具有固定的处理时间t,CPU应处理的截止期限d和周期p(比如时间片)
为什么硬实时系统处理时间要小于截止时间而不是小于周期?系统开销(比如延时)
硬实时:0<=t<=d<=p
t执行时间就是CPU运行时间,CPU利用率就是t/p
单调速率调度
抢占的,静态优先级
最优,但是CPU利用率是有限的,并不总是可能完成最大化CPU资源
最早截止期限优先调度
EDF,动态分配优先级
比例分享调度
准入控制策略:只有客户请求的股数小于可用的股数,才能允许客户进入
同步
解决共享数据并发访问导致数据不一致
竞争条件
临界区:修改公共变量,不允许多进程执行
进入区->临界区->退出区->剩余区
解决方案满足性质:互斥,进步,有限等待
两种方法:抢占式和非抢占式内核
一个进程进入临界区需要获得锁,退出时需要释放锁
忙等待
自旋锁:检查锁是否释放,浪费CPU周期,优点是没有切换上下文
信号量初值为可用资源数量
使用资源wait()减少信号量计数
释放资源signal()增加信号量计数
死锁与饥饿
相互持有共享资源,无法释放
优先级反转:所有正在访问资源的进程获得访问它的更高优先级进程的优先级,直到用完资源恢复优先级
内存
每个进程单独内存空间
两个寄存器:基地址,界限地址
保护:两者相加在范围里面,防止用户修改操作系统数据结构
特权指令,在内核模式下执行,修改这两个寄存器存储的值
地址绑定
进程在执行时可以在磁盘和内存之间移动,在磁盘上等待形成输入队列
编译时:绝对代码
加载时:可重定位代码
执行时:大多数采用,从一个内存段移动到另一个内存段
逻辑地址:CPU生成的地址(虚拟地址)
物理地址:
通过MMU内存管理单元映射,基地址寄存器变为重定位寄存器,用户进程加载到内存前都要加上重定位寄存器里面的位置,用户程序不会看到真实的物理地址
动态加载
一个程序只有在调用时才会加载,所有程序都以可重定位加载格式保存在磁盘上,提高内存空间利用率
交换
内存->快速磁盘/备份存储
标准交换:换入换出内存进程,上下文切换时间高
移动系统不支持交换,用闪存,由于空间约束
移动系统的交互:空闲内存降低到一定阙值以下时,IOS不采用交换,而是要求应用程序自愿放弃分配的内存
连续内存分配
- 为什么操作系统通常在低地址?
这取决于中断向量,一般中断向量位于低内存
内存保护:防止进程访问不属于它的内存,否则触发陷阱寻址错误
固定分区,每个分区只能由一个进程
可变分区,一大块可用内存,成为孔,内存有很多大小的孔
首次适应
最优适应
最差适应
内存碎片
存储被分成了大量小孔,总和能装下但是不连续,导致浪费
- 空空闲块的哪段开始分配
解决外部碎片:紧缩。需要重定位是动态的,在运行时进行,但是开销比较昂贵
分段
允许进程的物理地址空间是非连续的
用户试图的内存管理方案,从程序员视角
逻辑地址:段名称和段偏移(二维,段号和偏移)
编译的时候自动分段
从二维地址到物理一维地址,通过段表实现,段表就是基址寄存器和界限寄存器值,通过段号映射到段表中
- 段号怎么转换基地址?
分页
现在大多数操作系统使用
将物理内存分为固定大小的块(16kb),成为页帧;逻辑内存分为同样大小的快,称为页面
逻辑内存是连续的,但物理内存可能不是
CPU生成地址分成页码和页偏移,页码是页表的索引,页表和段表类似
页的大小为2的幂,地位表示页偏移,高位表示页码
不会产生外部碎片,但是可能有内存碎片,如果进程要求内存不是页的整数倍
内存中的帧要大于进程中的页
TLB转换表缓冲区
TLB命中:页面在TLB中
- 共享页
共享公共代码,但是每个进程有自己的数据页
可重入代码:不能自我修改,所以多个进程可以执行相同代码
页表结构
-
分层分页:减少内存所占页表空间,缺点但要多出一次访问
-
哈希页表
-
倒置页表:整个系统只有一个页表,每个条目保存一个地址空间标识符(PID)系统内每个虚拟地址<进程ID,页码,偏移>,每个地址<进程ID,页码>,减少了内存空间,但是增加查找空间
虚拟内存管理
允许执行进程不必完全处于内存
- 为什么在许多情况下并不需要将整个程序置于内存中?
1。程序有处理异常错误条件的代码,这些代码几乎不执行
2.数组,链表和表等分配的内存量通常多于实际需要值
3.程序的某些选项和功能可能很少使用
虚拟内存将逻辑内存和物理内存分开
-
请求调页:对于请求调页的虚拟内存,页面只有在程序执行期间被请求时才加载。调页程序会猜测在该进程被再次换出之前会用到哪些页,需要硬件支持来区分内存的页面和磁盘的页面,使用有效-无效位(不在逻辑内存里,或有效但只在磁盘上),这是系统试图改善几桶使用率和吞吐量
-
缺页错误:访问标记为无效的页面
-
页面置换:发生缺页错误,但是列表没有空闲帧,系统交换出一个进程释放所有帧并降低多道程序
-
页面置换算法:FIFO,调出最旧的页面;最优页面置换,调出置换最长时间不会使用的页面,LRU最近最少使用算法,基于计数的页面置换