[搞定面试] 操作系统

如果遇到喜欢问操作系统的面试官就自求多福吧,只能说 深不可测
本文只是粗略包含了一些基础知识点

前言

各种知识多而且容易遗忘,还不容易复习。最好的方法当然是自己给自己提问,不断补缺查漏,缺什么补什么。本文将各类知识归类,并将全文知识点浓缩在自问自查中,并且都写好目录,自问自查时可以随时跳转过去,方便大家系统的学习复习知识。 水平有限,有错误敬请指正

食用方法
自问自查---阅读原文---自问自查--阅读原文...
无限循环


自查自问

1. 进程和线程的区别
2. 僵尸进程孤儿进程
3. 调度算法
4. 进程间的通信
5. 死锁(条件与预防)&活锁&饥饿
6. 虚拟内存 
7. 分页分段段页
8. 内存和磁盘的关系
9. 随机读顺序读
10. 中断 内核态
10.写时拷贝
11.free命令
12.文件存储 

传送门(含目录)
数据库:https://blog.csdn.net/qq_45021207/article/details/113427419
计网分层:https://blog.csdn.net/qq_45021207/article/details/112387871
计网应用层:https://blog.csdn.net/qq_45021207/article/details/112723944
计网传输层:https://blog.csdn.net/qq_45021207/article/details/113184737
计网网络层&数据链路层 :https://blog.csdn.net/qq_45021207/article/details/113248814
操作系统 : https://blog.csdn.net/qq_45021207/article/details/113747408
java开篇: https://blog.csdn.net/qq_45021207/article/details/113770277

进程和线程的区别

本质上:进程是资源分配的基本单位,线程是任务调度的基本单位。

内存分配上:进程拥有独立的内存单元,而多个线程共享进程的内存(线程也有子集独立的栈空间,如程序计数器)。

开销:创建和撤销进程时系统需要为它分配和收集资源,所以远远比线程大,在进行进程切换时,涉及当前执行进程 CPU 环境的保存及新调度进程 CPU 环境的设置,而线程切换时只需保存和设置少量寄存器内容,开销很小。

通信:进程间以IPC(Inter-Process Communication,进程间通信)(管道,信号量,共享内存,消息队列,套接字等)方式通信 ;同一个进程下,线程间可以共享全局变量、静态变量等数据进行通信,做到同步和互斥,以保证数据的一致性。

健壮性:每个进程之间的资源是独立的,当一个进程崩溃时,不会影响其他进程;同一进程的线程共享此线程的资源,当一个线程发生崩溃时,此进程也会发生崩溃,稳定性差,容易出现共享与资源竞争产生的各种问题,如死锁等

线程的实现可以分为两类:
用户级线程:不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,在语言层面利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/内核态切换,速度快,操作系统内核不知道多线程的存在,因此一个线 程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少
内核线线程:又称为内核支持的线程或轻量级进程,所以需要切换到内核态。
在这里插入图片描述
协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。

进程切换与线程切换的最主要区别:进程切换涉及到虚拟地址空间的切换而线程切换则不会。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。把虚拟地址转换为物理地址需要查找页表,页表查找是一个很慢的过程,因此通常使用TLB(Translation Lookaside Buffer)来缓存页地址,用来加速页表查找。当进程切换后页表也要进行切换,页表切换后TLB就失效了,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致TLB失效,因为线程线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。

http://www.msdn.hk/jshtml/jswz/751.html
线程切换需要换切换必要的CPU寄存器

寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。

僵尸进程孤儿进程

在这里插入图片描述

调度算法

先来先服务:first-come first-serverd(FCFS)
按照请求的顺序进行调度,适合于长作业,因为短作业等的时间太长了。

短作业优先:
按估计运算时间的顺序进行排序,
长作业容易饿死,如果一直有短作业过来的话。

最短剩余时间:
按估计剩余时间最少的顺序进行调度。

时间片轮转:
安照FCFS的顺序进行排序,每次将队头的作业运行一个时间片,然后推到队尾
时间片算法的效率和时间片的大小有关系:如果太小进程频繁切换消耗过大,如果过大实时性得不到保障。

优先级调度:
按照给队列的优先级进行调度,防止低优先级的得不到调度可以随着时间提高优先级。

多级反馈队列:
在这里插入图片描述
多个队列,上面的优先级高,时间片小,s1都执行完然后到s2; 可以让小的碎片在上面都执行完,大的因为轮转片逐渐增大轮转的次数也会减少。 就像一个从上到下 筛子孔逐渐增大的筛子

进程间的通信

在这里插入图片描述
管道:只支持半双工通信(单向交替)
可以看出管道传输数据是单向的,如果想相互通信,我们需要创建两个管道才行。
所谓的管道,就是内核里面的一串缓存。从管道的一段写入的数据,实际上是缓存在内核中的,另一端读取,也就是从内核中读取这段数据。
管道这种通信方式效率低,不适合进程间频繁地交换数据。 因为管道里的内容没有被读取时会被阻塞,只有当管道里的数据被读完后,命令才可以正常退出。
它的好处,自然就是简单,同时也我们很容易得知管道里的数据已经被另一个进程读取了。

消息队列:
消息队列是保存在内核中的消息链表, A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。

消息队列不适合比较大数据的传输,因为在内核中每个消息体都有一个最大长度的限制
消息队列的通信不及时

共享存储:多个进程共享存储,需要用信号量解决同步问题 (效率最高)
消息队列的读取和写入的过程,都会有发生用户态与内核态之间的消息拷贝过程。那共享内存的方式,就很好的解决了这一问题。
共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。
在这里插入图片描述

信号量:计数器
用了共享内存通信方式,带来新的问题,那就是如果多个进程同时修改同一个共享内存,很有可能就冲突了。例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了。

P 操作是用在进入共享资源之前,V 操作是用在离开共享资源之后
信号量表示资源的数量,控制信号量的方式有两种原子操作:
*
一个是 P 操作,这个操作会把信号量减去 -1
*
另一个是 V 操作,这个操作会把信号量加上 1

例子: *
进程 A 在访问共享内存前,先执行了 P 操作,由于信号量的初始值为 1,故在进程 A 执行 P 操作后信号量变为 0,表示共享资源可用,于是进程 A 就可以访问共享内存。
*
若此时,进程 B 也想访问共享内存,执行了 P 操作,结果信号量变为了 -1,这就意味着临界资源已被占用,因此进程 B 被阻塞。
*
直到进程 A 访问完共享内存,才会执行 V 操作,使得信号量恢复为 0,接着就会唤醒阻塞中的线程 B,使得进程 B 可以访问共享内存,最后完成共享内存的访问后,执行 V 操作,使信号量恢复到初始值 1。

信号初始化为 1,就代表着是互斥信号量,它可以保证共享内存在任何时刻只有一个进程在访问
信号初始化为 0,就代表着是同步信号量 (A必须在B之前执行)
在这里插入图片描述
套接字:用于不同机器的通信

死锁&活锁&饥饿

1.死锁产生的条件:互斥,持有申请,不可剥夺,环路等待。

2.死锁代码

3.死锁的预防
临界资源需要互斥原则上不破坏互斥条件
规定所有程序在开始前就申请所有锁,这样会使并发性下降
规定进程在请求资源失败时,释放其资源
给资源编号,进程只能按照顺序请求资源

4.检测和回复
超时检测和遍历检测
检测到死锁后可以回滚事务,释放资源,之后再重做。
InnoDB 存储引擎使用检测是否存在环路的方式,并且选择将回滚操作代价小的事务进行回滚。

活锁&饥饿
活锁是指进程互相谦让,都释放资源给别的进程,导致资源在进程之间跳动但是进程却一直不执行。
饥饿是指将低优先级的进程长时间请求不到所需要的资源。但是饥饿中进程最后可以请求到资源,只要不再有高优先级的进程使用资源,这和死锁有所不同。

虚拟内存

虚拟内存是将物理内存扩充到更大的逻辑内存
在这里插入图片描述
一个虚拟地址包括两部分,一部分是页码另一部分是偏移量
页表存储着 虚拟内存到物理内存的映射;
在这里插入图片描述
虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

优点:
在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间,而不需要实际物理内存的连续空间,可以利用碎片

扩大了内存容量

当不同的进程使用同样的代码时,比如库文件中的代码,物理内存中可以只存储一份这样的代码,不同的进程只需要把自己的虚拟内存映射过去就可以了,节省内存

虚拟内存的缺点:
占用一定的物理硬盘空间;加大了对硬盘的读写;设置不得当会影响整机稳定性与速度。

各个进程需要缓存页表和读磁盘

分页和分段

分段是为了解决分页系统,在有动态增长是会产生的覆盖问题。

分段的做法是把内存分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。 段的大小需要程序猿自己划分

段页式
就是将内存分成独立段,然后将段分成大小相同的页。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

内存和磁盘

CPU
CPU是中央处理器的简称,它可以从内存和缓存中读取指令,放入指令寄存器,并能够发出控制指令来完成一条指令的执行。但是CPU并不能直接从硬盘中读取程序或数据。

内存
内存作为与CPU直接进行沟通的部件,所有的程序都是在内存中运行的。其作用是暂时存放CPU的运算数据,以及与硬盘交换的数据。也是相当于CPU与硬盘沟通的桥梁。只要计算机在运行,CPU就会把需要运算的数据调到内存中进行运算,运算完成后CPU再将结果传出来。

缓存
缓存是CPU的一部分,存在于CPU里。由于CPU的存取速度很快,而内存的速度很慢,为了不让CPU每次都在运行相对缓慢的内存中操作,缓存就作为一个中间者出现了。有些常用的数据或是地址,就直接存在缓存中,这样,下一次调用的时候就不需要再去内存中去找了。因此,CPU每次回先到自己的缓存(RAM)中寻找想要的东西(一般80%的东西都可以找到),找不到的时候再去内存中获取。

硬盘
我们都知道内存是掉电之后数据就消失的部件,所以,长期的数据存储更多的还是依靠硬盘这种本地磁盘作为存储工具。

简单的概括:
CPU运行时首先会去自身的缓存中寻找,如果没有再去内存中找。
硬盘中的数据会先写入内存才能被CPU使用。
缓存会记录一些常用的数据等信息,以免每次都要到内存中,节省了时间,提高了效率。
内存+缓存 -> 内存储空间
硬盘 -> 外存储空间

内存其实是磁盘的高速缓存,因为磁盘太慢了,而cpu太快,所以先把磁盘的东西拷贝到内存,然后再让cpu用。不用保存的数据可以暂时只放在内存,不用存到磁盘,停电就消失了。

顺序读,随机读

https://blog.csdn.net/u010087886/article/details/54405934?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

磁盘读取时间
①寻道时间,表示磁头在不同磁道之间移动的时间。
②旋转延迟,表示在磁道找到时,中轴带动盘面旋转到合适的扇区开头处。
③传输时间,表示盘面继续转动,实际读取数据的时间。
7200转/min,旋转一周需要8.33ms
寻道约10ms
所以整个磁盘读取时间在一个磁道上是10ms级的。

3.顺序读写和随机读写对于机械硬盘来说为什么性能差异巨大?

顺序读写=读取一个大文件
随机读写=读取多个小文件
顺序读写比随机读写快的原因
①顺序读写,主要时间花费在了传输时间,而这个时间两种读写可以认为是一样的。
随机读写,需要多次寻道和旋转延迟。而这个时间可能是传输时间的许多倍。
②顺序读写,磁盘会预读,预读即在读取的起始地址连续读取多个页面
(现在不需要的页面也读取了,这样以后用时就不用再读取,当一个页面用到时,大多数情况下,它周围的页面也会被用到)
而随机读写,因为数据没有在一起,将预读浪费掉了。
③另一个原因是文件系统的overhead。
读写一个文件之前,得一层层目录找到这个文件,以及做一堆属性、权限之类的检查。
写新文件时还要加上寻找磁盘可用空间的耗时。
对于小文件,这些时间消耗的占比就非常大了。
————————————————

中断&内核态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
内核态(Kernel Mode):运行操作系统程序

用户态(User Mode):运行用户程序

特权指令:只能由操作系统使用、用户程序不能使用的指令。 举例:启动I/O 内存清零 修改程序状态字 设置时钟 允许/禁止终端 停机

非特权指令:用户程序可以使用的指令。 举例:控制转移 算数运算 取数指令 访管指令(使用户程序从用户态陷入内核态)
在这里插入图片描述

Linux写时拷贝

学习过fork我们都知道是父进程创建出一个子进程,子进程作为父进程的副本, 是父进程的拷贝。
可是每次fork出的子进程难道还要把父进程的各种数据拷贝一份?有人会说不是父子进程不共享各种数据段吗?如全局变量区 ,栈区 , 堆区 。如果不拷贝那不就成共享的吗?其实有关子进程拷贝父进程的数据是这样的。
如果子进程只是对父进程的数据进行读取操作,那么子进程用的就是父进程的数据。如果子进程需要对某数据进行修改,那么在修改前,子进程才会拷贝出需要修改的这份数据,对这份备份进行修改。这就满足了父子进程的数据相互独立,互不影响的要求。这么做的初衷也是为了节省内存。 这就是写时拷贝技术,顾名思义,只在写的时候才拷贝的技术

fork返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

free 命令

free 命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。

swap space 是磁盘上的一块区域,可以是一个分区,也可以是一个文件。所以具体的实现可以是 swap 分区也可以是 swap 文件。当系统物理内存吃紧时,Linux 会将内存中不常访问的数据保存到 swap 上,这样系统就有更多的物理内存为各个进程服务,而当系统需要访问 swap 上存储的内容时,再将 swap 上的数据加载到内存中,这就是常说的换出和换入。交换空间可以在一定程度上缓解内存不足的情况,但是它需要读写磁盘数据,所以性能不是很高。

文件存储

linux :
https://blog.csdn.net/qq_38410730/article/details/81290855

一块大概 4kb
在这里插入图片描述
大小


自查自问

1. 进程和线程的区别
2. 调度算法
3. 进程间的通信
4. 死锁(条件与预防)&活锁&饥饿
5. 虚拟内存 
6. 分页分段段页
7. 内存和磁盘的关系
8. 随机读顺序读
9. 中断 内核态
10.写时拷贝
11.free命令
12.文件存储 
#面经#
全部评论
哈哈,有的图是王道考研的
点赞 回复
分享
发布于 2021-02-22 11:55

相关推荐

5 87 评论
分享
牛客网
牛客企业服务