操作系统面试知识点总结

操作系统面试知识点总结

一.操作系统概述

1.操作系统主要功能

  • 对计算机硬件资源进行管理,调度,分配
  • 向用户提供一个与系统交互的友好页面

2.操作系统的四个特征

操作系统拥有 4 个鲜明的特征:并发、共享、虚拟和异步。其中,并发和共享是操作系统的最基本特征,没有并发和共享,就谈不上虚拟和异步

  • 并发和并行

    • 并发:并发是指宏观上在一段时间内能同时运行多个程序。当然,这些程序宏观上是同时发生的,但微观上是交替发生的(同一时刻只有一个程序在执行)。操作系统通过引入进程和线程,使得程序能够并发运行
    • 并行:并行则指同一时刻能运行多个指令,指两个或多个事件在同一时刻同时发生并行需要硬件支持,如多流水线、多核处理器或者分布式计算系统。

    说到并发与并行,不得不提 CPU,作为计算机的大脑, CPU 主要和内存进行交互,从内存中提取指令并执行。而一个程序需要放入内存并给它分配 CPU 才能执行,所以并发并行的能力与 CPU 的性能息息相关:

    • 单核 CPU同一时刻只能执行一个程序,各个程序只能并发地执行 ;
    • 多核 CPU同一时刻可以同时执行多个程序,多个程序可以并行地执行。

    比如 Intel 的第八代 i3 处理器就是 4 核 CPU,意味着可以并行地执行 4 个程序。当然,即使是对于 4 核 CPU 来说,只要有 4 个以上的程序需要 “同时” 运行,那么并发性依然是必不可少的,因此并发性是操作系统一个最基本的特征

  • 共享

    共享即资源共享,是指系统中的资源可供内存中多个并发执行的进程共同使用。

    共享分为两类:互斥共享和同时共享

    互斥共享:虽然这个资源是共享的,所有进程都能够使用,但是同一个资源在某一时刻只允许一个进程访问,也称为互斥访问,需要用同步机制来实现互斥访问。互斥共享/访问的资源称为临界资源

    比如:如果我们同时使用 QQ 和微信视频,同一时间段内摄像头资源只能分配给其中的一个进程。

    同时共享:同时共享与互斥共享相反,允许一个时间段内多个进程 “同时” 对系统中的某些资源进行访问。当然,所谓的 “同时” 往往是宏观上的,而在微观上,这些进程可能是交替地对该资源进行访问(即分时共享)。

    比如:使用 QQ 发送硬盘上的文件 A,同时使用微信发送硬盘上的文件 B。宏观上看,两边在同时读取并发送文件, 都在访问硬盘资源,并从中读取数据。微观上看,QQ 和微信这两个进程是交替访问硬盘资源的。

  • 虚拟

    虚拟是指把一个物理上的实体变为若干个逻辑上的对应物。物理实体(前者)是实际存在的,而逻辑上对应物(后者)是用户感受到的。

    两种虚拟技术:空分复用,时分复用

    空分复用:比如虚拟内存:就是把内存作为高速缓存来使用,只用来保存最频繁使用的部分程序,而把程序的大部分放在磁盘上。这种机制需要快速的映像内存地址,以便把程序生成的地址转换为有关字节在内存中的物理地址。这种映像由 CPU 中的一个部件,称为存储器管理单元(Memory Management Unit,MMU)来完成。

    虚拟磁盘:物理磁盘虚拟为多个逻辑磁盘,如C、D、E等逻辑盘,使用起来更加安全、方便

    时分复用:多个进程能在同一个 CPU 上并发执行就是因为使用了时分复用技术,让每个进程轮流占用处理器,每次只执行一小个时间片并快速切换。 显然,如果失去了并发性,一个时间段内系统中只能运行一道程序,那也就失去了实现虚拟性的意义了。因此,没有并发性,就谈不上虚拟性

  • 异步和同步[1]:

    同步:所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
    换句话说,就是由调用者主动等待这个调用的结果。

    异步:而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者*,或通过回调函数处理这个调用。

    你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
    而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

3.阻塞与非阻塞

  • 阻塞是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
  • 非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程

你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。[1]

4.进程和线程

1)进程:是操作系统为各种程序分配资源的最小单位,(程序是一些保存在磁盘上的指令的有序集合),是程序的一次执行过程不仅包含正在运行的程序实体,并且包括这个运行的程序中占据的所有系统资源,比如说 CPU、内存、网络资源等

2)线程:是操作系统调度的最小单元,一个进程中可以有多个线程,它们共享进程资源

一个程序至少有一个进程,一个进程至少有一个线程

举个例子,QQ 和 Chrome 浏览器是两个进程,Chrome 进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。[2]

5.内核态和用户态

什么是内核

现代操作系统都采用进程的概念,为了更好的处理系统的并发性、共享性等,并使进程能够协调地工作,仅依靠计算机硬件提供的功能是远远不够的。例如,进程的调度就不能用硬件来实现,必须使用一组基本软件对硬件资源进行改造,以便为进程的执行提供良好的运行环境,这个软件就是内核(kernel)。简单的来说内核就是操作系统中的一组程序模块,作为可信软件来提供支持进程并发执行的基本功能和基本操作,具有访问硬件设备和所有内存空间的权限

当然,操作系统除了内核程序外,还有包括其他一些基本组件,如文本编辑器、编译器、用来与用户进行交互的程序比如桌面系统等。

image-20220225142244590

什么是内核态和用户态:

那么既然内核是程序,它需要运行,就必须被分配 CPU。因此,CPU 上会运行两种程序,一种是操作系统的内核程序(也称为系统程序),一种是应用程序。前者完成系统任务,后者实现应用任务。两者之间有控制和被控制的关系,前者有权管理和分配资源,而后者只能向系统申请使用资源

显然,我们应该把在 CPU 上运行的这两类程序加以区分,这就是内核态和用户态出现的原因

用户态和内核态其实就是CPU运行用户程序还是操作系统内核程序的表现

内核态:cpu运行操作系统内核程序时,CPU所处的状态是内核态,此时运行在内核态的程序可以访问计算机的任何资源,不受限制,为所欲为,例如协调 CPU 资源,分配内存资源,提供稳定的环境供应用程序运行等。

用户态:CPU运行用户程序所处的状态,运行在用户态的程序只能访问当前 CPU 上执行程序所在的内存地址空间,这样有效地防止了操作系统程序受到应用程序的侵害

6.内核态和用户态的转换

在合适的情况下,操作系统的内核会把 CPU 的使用权主动让给应用程序,也就是使 CPU 从内核态转换到用户态。而 CPU 要想从用户态回到内核态,只能通过中断机制完成,如果没有中断机制,那么一旦应用程序上 CPU 运行(用户态),CPU 就会一直运行这个应用程序。也就是说,中断是让操作系统内核夺回 CPU 使用权的唯一途径。可以说,操作系统是由中断驱动的

这里的中断机制具体指三种:系统调用,中断,异常

异常(也称内中断):当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态。比如缺页异常,如非法操作码、地址越界、算术溢出,除数为 0 等。

中断(狭义上的中断,也称外中断):外中断与当前执行的指令无关, 中断信号来源于 CPU 外部。如 I/O 完成中断,当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序。此外还有时钟中断、控制台中断等。

系统调用:用户态主动切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如 read 操作,fork() 操作(就是执行了一个创建新进程的系统调用)。说的更详细点,操作系统作为计算机硬件之上的第一层软件,需要向上层提供一些简单易用的服务,这个上层包括用户和应用程序:

image-20220225161743158

给用户提供的接口有图形界面 GUI 和命令接口,给应用程序提供的是程序接口,这个程序接口就是由一组系统调用组成的,是操作系统提供给开发人员使用的。可以理解为一种可供应用程序调用的特殊函数,应用程序可以通过系统调用来请求获得操作系统内核的服务

系统调用的过程简略版大致如下:

1)在用户态,应用程序传递系统调用参数

2)执行陷入指令(read,fork等等),引发一个内中断,使 CPU 进入内核态

3)在内核态,执行相应的请求,内核程序处理系统调用

4)返回应用程序


image-20220225161509621

二.系统调用

1.什么情况下会用到系统调用

举个例子:我们去学校打印店打印论文,你按下了 WPS 的 “打印” 选项,于是打印机开始工作。 你的论文打印到一半时,另一位同学按下了 Word 的 “打印” 按钮,开始打印他自己的论文。想象一下如果两个进程可以随意的、并发的共享打印机资源,会发生什么情况?

显然,两个进程并发运行,导致打印机设备交替的收到 WPS 和 Word 两个进程发来的打印请求,结果两篇论文的内容混杂在一起了

如何解决这个问题?这就需要操作系统内核对共享资源进行统一的管理,并向上层提供 “系统调用” ,运行在用户态的应用程序或者进程想要使用打印机这种共享资源,只能通过系统调用向操作系统内核发出请求,然后内核会对各个请求进行协调处理(进程调度)

通过上面这个例子,我们就可以总结出什么功能会用到系统调用:凡是与共享资源有关的操作(比如内存分配、I/O 操作、文件管理等),都必须通过系统调用的方式向操作系统内核提出请求,由操作系统内核代为完成。这样可以保证系统的稳定性和安全性,防止用户进行非法操作。

2.系统调用大致分为5类

这些系统调用按功能大致可分为如下几类:

  • 设备管理。完成设备的请求或释放,以及设备启动等功能。

    操作系统必须高效的管理 I/O 设备,它需要向 I/O 设备发送命令,捕捉中断,并处理设备的各种错误,它还应该在设备和系统的其他部分之间提供简单且易用的接口。

  • 文件管理。完成文件的读、写、创建及删除等功能。

    文件其实是进程创建的信息逻辑单元,一个磁盘可能含有几千甚至几百万个文件,每个文件都是独立于其他文件的,事实上,把每个文件看成一种地址空间更容易理解文件的本质。

    文件同样是受操作系统管理的,有关文件的构造、命名、存取、使用、保护、实现和管理方法都是操作系统设计的内容,这就是文件系统的主题。

  • 进程管理

    1)进程调度。完成进程的创建、撤销、阻塞及唤醒等功能。 通常情况下,会有多个进程或线程同时竞争 CPU,如果恰好只有一个 CPU 可用,这就导致 CPU 必须对下一个运行的进程或线程做出选择,这个选择的过程就是进程调度。

    2)进程通信。完成进程之间的消息传递或信号传递等功能。

    进程通信顾名思义,就是进程之间的相互交流。CPU 作为计算机最宝贵的资源,一个进程需要放入内存并给它分配 CPU 才能执行,而一个程序可能包含多个进程,这就需要进程之间进行相互交流,彼此同步,共同完成这个程序。举个例子,如果进程 A 产生数据而进程 B 打印数据,那么 B 在 A 产生数据之前就必须等待,那么 A 是不是就得给 B 发消息,告诉 B 我生产了数据,你可以打印了。

  • 内存管理。完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。

三.进程管理详解

1.进程和线程的创建和撤销过程

进程/线程的创建:

  • 申请PCB
  • 初始化进程描述信息
  • 为进程分配资源及地址空间
  • 将其插入就绪队列中

进程允许创建和控制另一个进程,前者称为父进程,后者称为子进程,子进程又可创建孙进程,子进程可以从父进程那里继承所有的资源,子进程撤销时便可将获得的资源归还。撤销父进程,必须撤销所有的子进程。

进程的撤销

  • 查找需要撤销的进程的PCB

  • 如果进程处于运行状态,则终止进程并进行调度

  • 终止其子孙进程,并归还资源

  • 将它从所在队列中删除

2.进程的五种状态

创建状态、就绪状态、运行状态、阻塞状态、结束状态

  • 只有就绪态和运行态能够相互转换,进程为就绪态时,等待cpu分配时间片,得到时间片后进入运行态
  • 运行态的进程使用完时间片后,又重新回到就绪态
  • 运行态的进程需要等待某个资源时(比如打印机资源),而进入阻塞态,阻塞态得到对应的资源时,又会回到就绪态

3.进程调度算法

按照系统的不同分为两大类:

3.1.批处理系统

  • 先来先服务

    非抢占式调度算法,按照进程请求顺序进行调度

  • 短作业优先

    按进程的估计运行时间,最短的优先执行

  • 最短剩余时间优先

    短作业优先的抢占式版本,按剩余时间的顺序进行调度。当一个新作业到达时,其整个隐形时间和当前进程的剩余时间相比,如果新的进程需要的时间更少,则挂起当前进程,运行新的进程。否则新进程等待。

3.2.交互式系统

  • 时间片轮转(时间片太小,导致进程切换频繁,浪费时间)

    将所有就绪进程按 FCFS 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。

  • 优先级调度

    为每个进程分配一个优先级,按优先级进行调度。为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。

  • 多级反馈队列

    时间片轮转调度算法和优先级调度算法的结合

    为进程设置多个队列,每个队列中进程的优先级和时间片都不同

    image-20220302202215475

4. 进程通信的方式

  • 创建管道进行通信。

    可以用 mkfifo 命令创建一个命名管道,可以用一个进程向管道里写数据,然后可以让另一个进程把里面的数据读出来。

  • 消息队列

    消息队列的通信模式是这样的:a 进程要给 b 进程发消息,只需要把消息挂在消息队列(可以是中介邮局,也可以是进程自己的信箱)里就行了,b 进程需要的时候再去取消息队列里的消息

  • 共享内存

    共享内存是最快的一种进程通信的方式,因为进程是直接对内存进行存取的。因为可以多个进程对共享内存同时操作,所以对共享空间的访问必须要求进程对共享内存的访问是互斥的。所以我们经常把信号量和共享内存一起使用来实现进程通信。(系统加载一个进程的时候,分配给进程的内存并不是实际的物理内存,而是虚拟内存空间。那么我们可以让两个进程各自拿出一块儿虚拟地址空间来,映射到同一个物理内存中。这样两个进程虽然有独立的虚拟内存空间,但有一部分是映射到相同的物理内存,这样就完成共享机制了)

5.死锁

5.1.发生死锁需要满足以下条件:

  • 互斥条件

    资源的分配是互斥的,资源要么处于被分配给一个进程的状态(此时其他进程不可用),要么就是可被其他进程可用状态

  • 等待和占有条件

    进程在请求资源得不到满足时,进入阻塞状态,且不是放已经占有的资源

  • 不剥夺条件

    已经分配给一个进程的资源不能强制性地被抢占,只能等待占有他的进程释放

  • 环路等待

    有两个或者两个以上的进程组成一条环路,该环路中的每个进程都在等待下一个进程释放所占有的资源

5.2.避免发生死锁

  • 预防策略

    破坏死锁发生的四个条件中的一个或者多个

  • 银行家算法

5.3.如果已经发生死锁如何消除

  • 撤销进程:
    • 撤消陷于死锁的全部进程;
    • 逐个撤消陷于死锁的进程,直到死锁不存在;
  • 资源剥夺,
    • 从陷入死锁的进程中逐个强迫放弃所占用的资源,直至死锁消失;
    • 从另外的进程那里强行剥夺足够数量的资源分配给死锁进程,以解除死锁状态

四.内存管理详解

1.内存管理的几种方式

  • 分块管理

    是连续管理的一种,把内存分为几个大小相等且固定的块,每个进程占用其中一个,如果进程很小的话,会浪费大量的空间。已经淘汰。

  • 分页管理

    把内存分为若干个很小的页面,相对比分块的划分力度更大一些。提高内存利用率。减少碎片,页式管理通过页表对应逻辑地址和物理地址。

  • 分段管理

    把内存分为几个大小不定的有实际意义的段,比如 main 函数段局部变量段代码段,通过管理段表来把逻辑地址转为物理地址。

  • 段页式管理

    结合了段式管理和页面管理的优点,把主存先分为若干个段,每个段又分为若干个页,也就是说段页式管理的段与段以及段的内部都是离散的

2.快表和多级页表

2.1.块表

块表又称为联想寄存器(TLB),是一种访问速度比内存快很多的高速缓冲存储器,用来存放当前访问的若干页表项(没有快表的话则需要到内存中访问页表,内存中的页表叫做慢表),来加速有逻辑地址到物理地址转换的速度。

2.2.块表中存放的是那些页表呢

根据局部性原理,被访问后的内存块儿很可能在短时间内再次被访问(因为程序中存在很多循环语句),可能程序在一段时间内会多次访问同一个页表项。所以在每次访问页表项时,先在快表里查询是否有该页表项,如果没有再去页表中查询,并把查到的页表项放入快表。如果快表满了,就根据一些策略把里面的页表项淘汰掉,再把新查询的页表加入进去。

2.3.多级页表

多级页表是为了解决页表在内存中占用空间太大的问题

在引入多级页表之前,我们使用单级页表来进行存储页表项,假如虚拟内存为 4GB,每个页大小为 4KB,那么需要的页表项就为 4GB / 4KB = 1M 个!每个页表项一般为 4B,那么就需要 4MB 的空间,大概需要占用 1000 个页来存页表项,存页表项花费了很多内存空间

所以如果引入两级页表,让一级页表的每个页表项不再映射 4KB,而是映射 4MB,那么需要的一级页表项的个数为 4GB / 4MB = 1K 个,再让每个一级的页表项映射 一个二级页表(二级页表中包含1K 个(1024个)二级页表项)

下面是一个二级页表逻辑地址转物理地址的例子

image-20220303102840611

3.虚拟地址和物理地址

我们写程序的时候,打交道的是虚拟地址。这个虚拟地址由操作系统决定,而物理地址指的是真实内存地址寄存器的地址。现代处理器通常使用虚拟寻址,用 MMU 把虚拟地址翻译成物理地址才能访问到真正的物理地址。

3.1.为什么要有虚拟地址

  • 没有虚拟地址,我们直接访问物理地址,这样用户程序可以直接访问底层物理地址,很容易破坏操作系统。造成系统崩溃
  • 想要同时运行多个程序特别困难,多个程序可能对同一个寄存器进行操作,会发生崩溃

4.虚拟内存

  • 传统的内存管理必须把作业一次性的 load 到内存中,并且一直驻留到其作业运行结束,当作业很大时,是没有办法一次性装入内存的
  • 而在一段时间内,只需要访问小部分数据就可以保证程序的正常运行。所以基于局部性原理,在程序加载的时候,把很快就会用到的部分放入内存中,暂时用不到的部分留在磁盘上。

其实虚拟内存的基础是局部性原理,也正是因为有局部性原理,程序运行时才可以做到只装入部分到内存就可以运行

5.虚拟内存的几种实现

5.1.请求分页式存储管理

建立在分页管理的基础之上,为了支持虚拟内存实现了请求调页和页面置换功能。

  • 首先作业运行时,仅装入当前要执行的部分页面即可
  • 在运行的过程中,发现要请求的页面不在内存中,那么处理器通知操作系统按照对应的页面置换算法把相应的页面调入到内存中。
  • 如果发现在把页面调入内存时,内存已满,同时也可以把不用的页面置换出去,以便腾出空间装入新的页面。

5.2.请求分段式存储管理

只是把分页管理换成了分段管理

5.3.请求段页式存储管理

同上

5.4.虚拟内存的请求分页存储管理和内存管理机制的不同

虚拟内存的请求分页式存储管理建立在分页管理之上,他们的根本区别是用不用把程序所需的全部地址空间 load 到内存里。请求分页式不需要全部 load 到内存中,而分页式管理需要,前者能够提供虚拟内存,后者不可以!

6.页面置换算法

当使用请求分页存储管理内存时,如果发生缺页中断(就是要访问的页面不在内存中,这时就需要操作系统把其调入主存后再进行访问)。且内存中没有空闲,此时就必须在内存中根据一定的方法来清空一些目前用不到的页面(内存),这样腾出空间来装新的内容。

6.1.先到先出算法(FIFO)

把在内存中停留时间最长的页面置换出去

6.2.最佳页面置换(OPT)

把后面永远用不到的或者最长时间用不到的内存页置换出去

6.3.最近最久未使用页面置换算法(LRU)

LRU算法给每个页面一个访问字段。来记录一个页面最近一次访问到现在经历的时间T,需要置换出一个页面时,把T最大的那个页面置换出去即可

6.4.最少使用算法LFU

把使用最少的页面淘汰掉

五.参考

  1. 怎样理解阻塞非阻塞与同步异步的区别? - 知乎 (zhihu.com)
  2. 时间宝贵,操作系统核心知识复习路线!_技术交流_牛客网 (nowcoder.com)
  3. 高频知识汇总 | 【操作系统】面试题汇总(万字长文通俗易懂)_笔经面经_牛客网 (nowcoder.com)
posted @ 2022-04-03 19:36  rain-1227  阅读(479)  评论(0)    收藏  举报