面试中那些操作系统常考问题

1. 进程和线程以及其区别?
1、进程是系统进行资源调度和分配的的基本单位,是程序的一次动态执行过程,可实现操作系统的并发;线程是系统资源调度的在最小单位,可实现进程内部的并发;
2、一个程序至少包含一个进程,一个进程至少包含一个线程,线程是进程的子任务;
3、进程有自己独立的内存单元,线程没有,多个线程共享一个进程的内存;

2. 进程间通信的方式?
1、管道:内存中固定大小的缓冲区;一个管道只能实现半双工通信,要实现全双工通信需要两个管道;数据没读空不能写,没写满不能读;
优缺点:简单,能保证数据确实已经被取出了(因为没读空是不能写的),但效率低。如a进程给b进程传输数据,只能等到b取出数据后才能返回。因此,其不适合频繁通信的进程。
能否将进程的数据放在某个内存之后不用等待其他进程来取就返回呢?
2、消息队列:a进程给b进程传输数据,把消息放在对应的消息队列即可,无需等待。
优缺点:如果a进程发送的数据占用内存较大,且两进程通信特别频繁,消息队列就不合适了。因为此时大量时间花费在内存的拷贝上。
如何解决上述拷贝耗时问题呢?
3、共享内存:a和b进程各自拿出一块虚拟内存地址空间,然后映射到同一个物理内存中,实现内存共享机制。
但是上述共享内存机制存在多进程竞争内存的问题,如何解决呢?
4、信号量:本质是计数器,用来实现进程之间的互斥和同步。比如信号量初值为1,a进程来访问内存时,将信号量置为0,当b进程也来访问这个内存时,看到信号量为0,就知道该内存已经被使用了。
5、套接字(socket):上述机制都是多个进程在一台主机之间的通信。不同主机之间的进程通信用套接字。
socket由IP地址和端口号组成,本质上是编程接口。

3. 进程同步机制?
原子操作、信号量、自旋锁管程、会合、分布式系统

4. 线程同步的方式?
1、互斥量:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问;
2、信号量:允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量;
3、事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。

5. 进程有哪几种状态?各个状态如何转换?
包括以下5种状态:
五种状态
各个状态之间的转换关系如下:
状态转换关系

6. 同一进程间的线程共享以及独享的资源有哪些?
共享:
a. 堆,由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;
b. 全局变量,它是与具体某一函数无关的,所以也与特定线程无关;
c. 静态变量,虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的;
d. 文件等公用资源,使用这些公共资源的线程必须同步。
独享:
a. 栈
b. 寄存器的值

7. 对协程的认识?
协程是一种轻量级的线程,可以实现单线程下多任务,它通过 yield 关键字来实现,能有效地减少多线程之间切换的开销。
正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。它相当于一个特殊的函数,可以在某个地方挂起,并且可以重新在挂起处继续运行。
一个线程内的多个协程的运行是串行的。当一个协程运行时,其他协程必须挂起。它的切换者和切换时机是用户的应用程序决定,而不是操作系统。

协程的特点?
a、不被操作系统内核所管理,而是由程序所控制(也就是在用户态执行),性能得到了很大的提升,不会像线程切换那样消耗资源;
b、缺点:协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程。

8. 什么是死锁?死锁产生的条件及如何处理?
1、概念
在两个或者多个并发进程中,如果每个进程持有某种资源而又等待其它进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称该组进程产生了死锁。通俗的讲,就是两个或多个进程无限期的阻塞、相互等待的一种状态
2、死锁产生的四个必要条件
(1)互斥:至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其他申请使用该资源,那么申请进程必须等到该资源被释放为止;
(2)占有并等待:一个进程必须占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有;
(3)非抢占:进程不能被抢占,即资源只能被进程在完成任务后自愿释放;
(4)循环等待:若干进程之间形成一种头尾相接的环形等待资源关系。
3、死锁的处理策略和方法?
不允许死锁发生:预防死锁(静态策略)、避免死锁(动态策略)、允许死锁发生:死锁的解除
(1)预防死锁(静态)
思想:破坏死锁产生的四个必要条件其中任意一个即可
静态策略
(2)避免死锁(动态)
基本思想是动态检测资源分配状态,以确保循环等待条件不成立,从而确保系统处于安全状态。
安全状态:如果系统能按某个顺序为每个进程分配资源(不超过其最大值),那么系统状态是安全的,换句话说就是,如果存在一个安全序列,那么系统处于安全状态。
两种死锁避免算法
资源分配图算法和银行家算法,其可以确保系统始终处于安全状态。其中,资源分配图算法应用场景为每种资源类型只有一个实例(申请边,分配边,需求边,不形成环才允许分配),而银行家算法应用于每种资源类型可以有多个实例的场景。
(3)死锁的解除方法
资源剥夺法:挂起()某些死锁进程,并抢占其资源,将这些资源分配给其他死锁进程。但是应防止被挂起的进程因长时间得不到资源而饥饿。
撤销进程法:强制撤销部分或全部死锁进程,并剥夺这些进程的资源。该方法实现简单,但是可能代价很大。因为有些进程可能已经运行很长时间接近结束,一旦被终止需从头再来。
进程回退法:让死锁的进程回退到足以避免死锁的地步。这就要求系统记录进程的历史信息,设置还原点。

检测到死锁后如何决定对哪些进程动手?
需考虑:进程优先级、已执行的时间、还要多久完成、进程已经使用了多少资源等

9. 死锁、饥饿和死循环的区别?
区别

10. 用户态和内核态区别?
它们是操作系统的两种运行级别,最大的区别就是特权级不同。用户态拥有最低的特权级(3级),内核态拥有较高的特权级(0级)。运行在用户态的程序不能直接访问操作系统内核数据结构和程序。

当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(3级)用户代码中运行。

11. 用户态与内核态之间如何转换?
内核态到用户态:执行一个特权指令将程序状态字(PSW)的标志位设置为用户态。
用户态到内核态:中断是唯一途径。主要包括三种方式,
a. 系统调用
如打开某一设备、创建文件等。
b. 异常
如缺页异常。
c. 外围设备的中断
比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
这3种方式其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。

12. 操作系统中进程调度策略有哪些?
共有六种,交互性较差的3种,较好的3种。
交互性较差:先来先服务(FCFS),短作业优先(SJF/SPF),高响应比优先(HRRN)。
交互性差
交互性较好:时间片轮转,优先级调度,多级反馈队列。
交互性好
13. 多线程和多进程的区别?
进程是资源分配的基本单位,而线程时CPU调度的最小单位。
多线程之间共享同一个进程的地址空间,线程间通信简单,同步复杂,线程创建、销毁和切换简单,速度快,占用内存少,适用于多核分布式系统,但是线程间会相互影响,一个线程意外终止会导致同一个进程的其他线程也终止,程序可靠性弱。
多进程间拥有各自独立的运行地址空间,进程间不会相互影响,程序可靠性强,但是进程创建、销毁和切换复杂,速度慢,占用内存多,进程间通信复杂,但是同步简单,适用于多核、多机分布。

14. 什么是缓冲区溢出?有什么危害?其原因是什么?
指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
危害:
程序崩溃,导致拒绝额服务;跳转并且执行一段恶意代码。
主要原因:是程序中没有仔细检查用户输入。

15. 并发和并行,阻塞非阻塞,同步和异步?
并发:宏观上看起来两个程序在同时运行,但是从微观上看两个程序的指令是交织着运行的。这种并发并不能提高计算机的性能,只能提高效率。(你有处理多个任务的能力,不一定同时)
并行:严格意义上的同时运行。比如多核cpu,两个程序分别运行在两个核上,两者之间互不影响,单个周期内每个程序都运行了自己的指令。(你有同时处理多个任务的能力)
阻塞和非阻塞:调用者在事件没有发生的时候,一直在等待事件发生,不能去处理别的任务这是阻塞。
调用者在事件没有发生的时候,可以去处理别的任务这是非阻塞。
同步和异步:调用者必须循环自去查看事件有没有发生,这种情况是同步。
调用者不用自己去查看事件有没有发生,而是等待着注册在事件上的回调函数通知自己,这是异步。

16. 微内核与宏内核?
微内核与宏内核

17. 5种IO模型?
1、阻塞IO: 调用者调用了某个函数,等待这个函数返回,期间什么也不做,不停的去检查这个函数有没有返回,必须等这个函数返回才能进行下一步动作。
2、非阻塞IO: 非阻塞等待,每隔一段时间就去检测IO事件是否就绪。没有就绪就可以做其他事。
3、信号驱动IO: linux用套接口进行信号驱动IO,安装一个信号处理函数,进程继续运行并不阻塞,当IO时间就绪,进程收到SIGIO信号。然后处理IO事件。
4、IO复用/多路转接IO: linux用select/poll函数实现IO复用模型,这两个函数也会使进程阻塞,但是和阻塞IO所不同的是这两个函数可以同时阻塞多个IO操作。而且可以同时对多个读操作、写操作的IO函数进行检测。知道有数据可读或可写时,才真正调用IO操作函数。
5、异步IO: linux中,可以调用aio_read函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。

为了便于记忆,可以类比以下钓鱼的例子:
阻塞:没鱼上钩之前你一直看着,等待鱼上钩期间什么也不能做;
非阻塞:鱼没上钩前你可以干别的事,比如你玩玩手机,再看看鱼是否上钩;
信号驱动:你再鱼竿上安装一个铃铛,然后你就去干别的了。只要铃铛一响你就知道收竿了;
复用:直接放100根鱼竿,几乎不用等待,一直在收竿;
异步:你是老板,你业务很忙,把钓鱼的事让司机去做,钓到鱼后再通知你。

18. 什么是内存对齐,为什么要内存对齐?
内存对齐是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。
原因:
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

关于内存对齐的一个例子:
typedef struct {
int a;
double b;
short c;
}A;

typedef struct {
int a;
short b;
double c;
}B;
分别对他们求大小,sizeof(A),sizeof(B)我们所得到的结果是不同的,
sizeof(A)=24而sizeof(B)=16 为什么会产生不一样的结果呢?

在结构体中,从结构体的首地址开始,假设地址从0开始。
对结构体A来说,a占4个字节,占从0–3的字节,b是double类型占8个字节,占从8–15的字节,c占两个字节,从16–17的字节。
对结构体B来说,a占4个字节,从0–3,b占两个字节从4–6;c占8个字节从8–15。

这就是内存对齐,对齐规则是按照成员的声明顺序,依次安排内存,其偏移量为成员大小的整数倍,0看做任何成员的整数倍,最后结构体的大小为最大成员的整数倍(所以这里的A的大小是24,而不是18)。

19. 分页和分段有什么区别?
(1)段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明(不可见)的。
(2)段的大小不固定,有它所完成的功能决定;页大大小固定,由系统决定
(3)段向用户提供二维地址空间(段名+段内地址);页向用户提供的是一维地址空间
(4)段更便于信息的共享和保护。
(5)分段和分页(单级页表)访问一个逻辑地址都需要两次访存,分段也可以引入快表机构。
快表是一种特殊的高速缓冲存储器(Cache),内容是页表中的一部分或全部内容。引入快表是为了加快地址映射速度。引入快表后只需要一次访存。

内部碎片和外部碎片?
内部碎片就是已经被分配出去却不能被利用的内存空间;
外部碎片指的是还没有被分配出去,但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。
分页不产生外部碎片,分段会产生外部碎片(紧凑技术可解决,但是时间代价大)。

20. 虚拟内存的定义和特征?
定义:程序不需要全部装入即可运行,运行时根据需要动态调入数据,若内存不够还需换出一些数据;
特征
多次性:作业运行时无需一次性全部装入内存,而是允许被分成多次调入内存;
对换性:作业运行时无需一直常驻内存,而是在运行过程中,允许将作业换入换出;
虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量远大于实际容量。

局部性原理(虚拟内存技术基于局部性原理)
(1)时间上的局部性:最近被访问的页在不久的将来还会被访问;
(2)空间上的局部性:内存中被访问的页周围的页也很可能被访问。

实现虚拟内存技术需要实现两个功能,即请求调页和页面置换
请求调页:访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存;
页面置换:内存空间不够时,将内存中暂时用不到的信息换出到外存。

21. 页面置换算法有哪些?
页面置换算法

22. 内存池、进程池、线程池的概念?
池化技术概念:提前保存大量的资源,以备不时之需以及重复使用。池化技术应用广泛,如内存池,线程池,连接池等等。
为什么需要池化技术
在实际应用中当进行分配内存、创建线程进程时都会涉及系统调用,而系统调用需要程序从用户态切换到内核态,这是非常耗时的操作。因此,当程序中需要频繁的进行内存申请释放,进程、线程创建销毁等操作时,通常会使用池化技术来提升程序的性能。
线程池:先启动若干数量的线程,并让这些线程都处于睡眠状态,当需要一个开辟一个线程去做具体工作时,就会唤醒线程池中的某一个睡眠线程,让它去做该工作,完成后,线程又处于睡眠状态,而不是将线程销毁。
进程池与线程池同理。
内存池:指程序预先从操作系统申请一块足够大内存,此后,当程序中需要申请内存的时候,不是直接向操作系统申请,而是直接从内存池中获取;同理,当程序释放内存的时候,并不真正将内存返回给操作系统,而是返回内存池。当程序退出(或者特定时间)时,内存池才将之前申请的内存真正释放。

23. 什么是颠簸现象?
指在页面调度中页面被频繁的换入换出的现象。因此,会不断产生缺页中断,导致整个系统的效率急剧下降,这种现象称为颠簸(抖动)。
主要原因:分配给进程的物理块不够。

内存颠簸的解决策略包括:
如果是因为页面替换策略失误,可以修改替换算法来解决这个问题;
如果是因为运行的程序太多,造成程序无法同时将所有频繁访问的页面调入内存,则要降低多道程序的数量;
否则还剩下两个办法:终止该进程或增加物理内存容量。

24. 什么是上下文切换?
上下文切换是一种将CPU资源从一个进程分配给另一个进程的机制。从用户角度看,计算机能够并行运行多个进程,这是操作系统通过快速上下文切换造成的结果。在切换的过程中,操作系统需要先存储当前进程的状态(包括内存空间的指针,当前执行完的指令等等),再读入下一个进程的状态,然后执行此进程。

进程上下文切换与线程上下文切换最主要的区别
线程切换虚拟内存空间是相同的(因为都是属于自己的进程),但进程切换的虚拟内存空间则是不同的,且进程切换开销大。

25. 互斥锁、自旋锁、乐观锁、悲观锁?
互斥锁:在访问共享资源之前对互斥量进行加锁,访问完成后释放该锁。如果在加锁之后没释放锁之前其他线程要对资源进行访问,则这些线程会被阻塞睡眠(不占用cpu),直到解锁。如果解锁时有一个或者多个线程阻塞,那么这些锁上的线程就都会变成就绪状态,但是只有第一个变为就绪状态的线程才能获得资源的使用权,并且再次加锁,其他线程继续阻塞等待。
自旋锁:一种特殊的互斥锁,资源被加锁后,其他线程想要再次加锁,此时线程不会被阻塞睡眠,而是进入循环等待状态(不做其他事),循环检查资源持有者是否已经释放了资源。好处是减少了线程从睡眠到唤醒时的资源消耗,但缺点是一直占用cpu。适用于资源被锁住时间短的情况。
悲观锁:就是比较悲观,总假设最坏的情况,即每次去拿数据的时候都认为别人会修改,所以每次拿数据时都会上锁,这样别人想拿这个数据时会被阻塞,直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转给其它线程)。
乐观锁:就是比较乐观,总假设最好的情况,即每次去拿数据时都认为别人不会修改,也就不会上锁,但在更新时会判断一下在此期间有没有别人去更新这个数据。乐观锁适用于多读少写的情况,可以提高吞吐量。
 
 
 
 

在这里插入图片描述

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值