zoukankan      html  css  js  c++  java
  • 操作系统常见面试题

    参考:

    多进程和多线程的区别是什么?多进程和多线程的优缺点分析

    协程与线程的区别

    进程、线程和协程之间的区别和联系

    1、操作系统的四个特性

    并发:同一段时间内多个程序执行(与并行区分,并行指的是同一时刻有多个事件,多处理器系统可以使程序并行执行)

    共享:系统中的资源可以被内存中多个并发执行的进线程共同使用

    虚拟:通过分时复用(如分时系统)以及空分复用(如虚拟内存)技术把一个物理实体虚拟为多个

    异步:系统进程用一种走走停停的方式执行,(并不是一下子走完),进程什么时候以怎样的速度向前推进是不可预知的

    2、多线程相较单线程的好处

    1、并发提升程序执行效率 
    2、提升CPU利用率,访存的时候可以切换线程来执行
    3. 更快的响应速度,可以有专门的线程来监听用户请求和专门的线程来处理请求。比如监听线程和工作线程是两个线程,这样监听就负责监听,工作的就负责工作,监听到用户请求马上把请求转到工作线程去处理,监听线程继续监听

    3、使用多线程的可能带来的问题

    内存泄漏、上下文切换、死锁还有受限于硬件和软件的资源闲置问题。线程崩溃可能导致整个进程崩溃

    4、知道多线程和多进程的区别吗?各自有什么优点呢

    在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位。

    多进程优点:

      1、每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系;

      2、通过增加CPU,可以容易得扩充性能;

      3、可以尽量减少线程加锁/解锁操作,极大提高性能,就算是线程运行的模块算法效率低也没关系;

    多进程缺点:

      1、逻辑控制复杂,需要和主程序交互;

      2、多进程调度开销比较大,需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算 ;

    多线程的优点:

      1、程序逻辑和控制方式简单;

      2、拥有资源少,线程调度开销小,无需跨进程边界;

      3、同一个进程的所有线程可以直接共享内存和变量

           4、因为cpu调度的粒度更细,所以cpu利用率更高

    多线程缺点:

      1、线程之间的同步和加锁控制比较麻烦;

      2、一个线程的崩溃可能影响到整个程序的稳定性;因为线程没有地址空间,它只是一个进程的执行路径,进程是比较健壮的。

      3、到达一定的线程数程度后,即使再增加CPU也无法提高性能,,而且线程多了之后线程本身的调度也需要消耗较多的CPU

    进程和线程的区别:

    1. 基本单位:进程是分配资源的基本单位,而线程是独立运行和独立调度的基本单位。也就是说 进程不能执行,真正执行的是进程里的线程。

    2. 健壮性:进程有独立的地址空间,有独立的资源,子进程崩溃不会对主进程造成影响;而线程没有自己的地址空间,只是进程的一个执行路径,所以一个线程的崩溃可能会影响整个进程的稳定性。

    3. 调度开销:进程因为拥有的资源多,所以调度开销大,线程的调度开销小。

    5、线程与协程的区别

    协程

    协程是一种用户态的轻量级线程,协程不是由操作系统内核管理,而是完全由用户程序所控制,这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。协程可以理解为可以暂停执行的函数。它拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

    线程和协程的区别:

    1、线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
    2、线程是协程的资源。协程通过 可以关联任意线程或线程池的执行器(Interceptor)来间接使用线程的资源的。

    协程相较于多线程的优势:

    1.因为协程这个子程序切换不是线程切换,而是由程序自身控制,因此没有线程切换的开销
    2.  极高的执行效率:因为只有一个线程,也不存在同时写变量冲突,在控制共享资源时就不需加锁,所以执行效率比多线程高很多。

    6、什么是死锁,产生死锁的四个条件,怎么避免死锁

    一个进程集合中的每一个进程都在等待只能由该集合中的其他进程才能引发的事件,那么该组进程进入死锁状态。由于集合中的每一个进程都在等待集合中的另一个进程释放资源,但由于它们都已经处于等待状态而无法执行,所以它们谁也不会释放资源,结果是这组进程都将无法再继续向前推进。

    四个条件:

    • 互斥条件:该资源任意一个时刻只由一个线程占用。
    • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    • 不剥夺条件:线程已获得的资源在末使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

    如何避免:

    我们只要破坏产生死锁的四个条件中的其中一个就可以了。

    破坏互斥条件

    这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。

    破坏请求与保持条件

    一次性申请所有的资源。

    破坏不剥夺条件(Synchronized无法破坏这个条件,所以引入了ReetrantLock)

    占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。

    破坏循环等待条件

    靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

    7、虚拟内存+内存分页

    虚拟内存

    虚拟存储器就是具有请求调入功能,能从逻辑上对内存容量加以扩充的一种存储器系统,虚拟内存有多次性,对换性和虚拟性三个特征,它可以将程序分多次调入内存,使得在较小的用户空间可以执行较大的用户程序,所以同时容纳更多的进程并发执行,从而提高系统的吞吐量。发生缺页时可以调入一个段也可以调入一个页,取决于内存的存储管理方式。虚拟性表示虚拟内存和物理内存的映射
        Linux下,进程不能直接读写内存物理地址,只能访问【虚拟内存地址】
        操作系统会把 虚拟内存地址-->物理地址
        
        虚拟内存解决
            有限的内存空间加载较大的应用程序
            根据需要在内存和磁盘之间来回传送数据
        
        通过段页表的形式,虚拟内存中取一段连续的内存空间映射到主内存中,主内存空间的程序段可以不连续

    缺页异常

        进程在访问某个虚拟内存地址时,
        操作系统翻译虚拟内存地址两种{
            1. 没有缺页,获取到内存物理地址
            2. 磁盘,发生缺页异常。
                进程中断,读取磁盘内的对应页进入内存。进程进入就绪状态
        }

    内存分页

    若按照【字节】为单位,进行 虚拟内存和物理内存的映射,【内存空间不足以存储这么多映射关系】
    
    因此linux提出【内存分页】,以每页4kb为单位进行映射
    使得内存中的记录变为原先的四千分之一
    
    虚拟内存地址{
        1. 前20位 【页编号】
        2. 后12位 【偏移量】
    } 

    8、基本分页储存管理方式

    把主存空间划分为大小相等且固定的页,作为主存的基本单位,每个进程也以页为单位进行划分,进程执行时,以页为单位逐个申请主存中的叶空间。用页表记录分散的内存分布情况。

    页表

    用来记录逻辑地址和实际存储地址之间的映射关系,以实现从页号到物理块号的映射。

    访问分页系统中内存数据需要两次内存访问,一次从内存中访问页表,找到实际物理地址,第二次根据得到的物理地址访问指定的内存块

    逻辑空间->页表->物理空间

    快表机制:

    可以说是存储在寄存器中的页表,功能和页表一样,也是提供一个逻辑地址物理地址的映射关系,但是它的容量更小,查询速度也更快。所以快表中存储的是访问最频繁的那些页,访问内存数据的时候先在快表里查询,如果查到了就可以直接读取相应的物理块号,如果没找到再访问页表,得到物理地址并访问,同时把该页表中的该映射项添加到快表中

    两级页表或多级页表

    9、基本分段储存管理方式

    分段管理:每个段内部连续内存分配,但段与段之间是离散的,因此会用到段表,记录每段在内存中的起始地址和该段长度。

    段表可以放在内存或寄存器中。

    10、分页和分段的比较

    页是信息的物理单位,是出于系统内存利用率的角度提出的离散分配机制;

    段是信息的逻辑单位,每个段存储一段意义完整的信息,是出于用户角度提出的内存管理机制

    页的大小是固定的,由系统决定;

    段的大小是不确定的,由用户决定

    页面置换算法

    为什么要页面置换:

    因为应用程序是分多次装入内存的,所以运行到一定的时间,一定会发生缺页。地址映射的过程中,如果页面中发现要访问的页面不在内存中,会产生缺页中断。此时操作系统必须在内存里选择一个页面把他移出内存,为即将调入的页面让出空间。选择淘汰哪一页的规则就是页面置换算法

    分类:

    最佳置换算法(理想):将当前页面中在未来最长时间内不会被访问的页置换出去

    先进先出:淘汰最早调入的页面

    最近最久未使用 LRU每个页面有一个t来记录上次页面被访问直到现在,每次置换时置换t值最大的页面(用寄存器或栈实现)

    时钟算法clock(也被称为最近未使用算法NRU):页面设置访问为,将页面链接为一个环形列表,每个页有一个访问位0/1, 1表示又一次获救的机会,下次循环指针指向它时可以免除此次置换,但是会把访问位置为0, 代表他下次如果碰到循环指针就该被置换了。页面被访问的时候访问位设为1。页面置换的时候,如果当前指针的访问位为0,置换,否则将这个值置为0,循环直到遇到访问位为0的页面。

    改进型Clock算法:在clock算法的基础上添加一个修改位,优先替换访问位和修改位都是0的页面,其次替换访问位为0修改位为1的页面。

    最少使用算法LFU:设置寄存器记录页面被访问次数,每次置换当前访问次数最少的

    11、操作系统中进程和线程的同步和通信机制

    进程的同步机制:临界区、信号量同步机制、管程同步机制
    线程的同步机制:synchronized reentrantLock, volatile
    进程通信:信号、管道、FIFO、消息队列、信号量、共享内存、套接字
    线程的通信:wait/notify 、volatile、CountDownLatch、CyclicBarrier

    进程间的通信方式

    信号:编写自己的信号响应函数或者调用系统的信号响应函数做出相应的响应
    匿名管道(半双工,读写端固定,只能父子进程通信,管道文件内存中)
    有名管道(FIFO):(任何进程通信,顺序写入,服务器监视FIFO文件,读出清除)
    消息队列(异步通信机制,存放在内核中并由消息队列标识符标识,消息含队列ID支持随机读取,独立于发送、接收进程 进程终止时消息不清空)
    信号量(本质是计数器,实现进程【同步互斥】,PV原子性操作),用来控制多个进程对资源的访问,它通常作为一种锁机制。
    共享内存区(直接对【内存】读取,通过信号量实现多线程安全)
    socket(创建套接字,然后绑定一个端口,监听套接字,可以通过网络连接不同计算机上的进程进行通信)

    12、线程有哪些状态?

    操作系统分类:创建,就绪,运行,阻塞,结束
    Java分类:创建,运行,阻塞,限期等待,非限期等待,结束

    13、Java 中用到的线程调度

    抢占式调度:

    抢占式调度指的是每条线程执行的时间、线程的切换都由系统控制,不由线程本身决定,所以一个线程的堵塞不会导致整个进程堵塞。

    协同式调度:

    线程的执行时间由线程本身控制,线程把自己的工作执行完了之后,主动通知系统切换到另一个线程去。有点是实现简单,缺点是可能导致整个系统崩溃。

    JVM 的线程调度实现(抢占式调度)

    java 使用的线程调使用抢占式调度,Java 中线程会按优先级分配 CPU 时间片运行,且优先级越高越优先执行,但优先级高并不代表能独自占用执行时间片,可能是优先级高得到越多的执行时间片,反之,优先级低的分到的执行时间少但不会分配不到执行时间。

    14、进程调度的算法

    先来先服务、短作业优先;优先权(抢占式,非抢占式、高响应比);时间片轮转、多级反馈队列

    优先级调度算法

    1. 先来先服务调度算法(FCFS)
    就绪队列
    2. 短作业(进程)优先调度算法

    高优先权优先调度算法

    1. 非抢占式优先权算法
    2. 抢占式优先权调度算法
    3.高响应比优先调度算法
    (1) 如果作业的等待时间相同,则要求服务的时间愈短,其优先权愈高,因而该算法有利于
    短作业。
    (2) 当要求服务的时间相同时,作业的优先权决定于其等待时间,等待时间愈长,其优先权
    愈高,因而它实现的是先来先服务

    基于时间片的轮转调度算法

    多级反馈队列调度算法

    15、用户态和核心态

    内核态:cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。

    用户态:只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。

    最大的区别就是权限不同,在运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。

        指令分为 特权指令和非特权指令
        其中 特权指令必须在核心态执行,如 启动IO /内存清零 /修改程序状态字
            内核速度快但是资源有限,能控制的进程数不多,所以需要速度少慢一些的用户态协助
            内核调度、非内核调度

    为什么要有这两态:

    内核速度快但是资源有限,能控制的进程数不多,所以需要速度慢一些的用户态协助,但是为了避免用户态被恶意利用,所以限制了用户态程序的权限。

    需要限制不同的程序之间的访问能力,防止他们获取别的程序的内存数据,或者获取外围设备的数据,并发送到网络,CPU划分出两个权限等级 -- 用户态和内核态。

    什么时候转换

    1、系统调用

    用户进程主动发起的。用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如fork()就是执行一个创建新进程的系统调用

    用户程序使用系统调用,系统调用会转换为内核态并调用操作系统

    2、发生异常

    会从当前运行进程切换到处理次此异常的内核相关程序中

    3、外围设备的中断:
    所有程序都运行在用户态,但在从硬盘读取数据、或从键盘输入时,这些事情只有操作系统能做,程序需要向操作系统请求以程序的名义来执行这些操作。这个时候用户态程序切换到内核态。

    用户接口程序(GUIshell

    GUIGraphical User Interface,图形用户界面,带有图形界面的操作系统;基于文本、命令行的叫shell,处于用户态中,位于用户态的最底层,允许用户运行其他程序(而操作系统运行在内核态中)

  • 相关阅读:
    使用SignTool对软件安装包进行数字签名(二)--进行数字签名
    使用SignTool对软件安装包进行数字签名(一)--制作证书
    三角形相关算法--求解三角形顶点坐标
    子网掩码与子网个数、主机地址个数的关系
    pgsql中的lateral使用小结
    Git中rebase失败了如何进行恢复
    灰度发布
    go 中的WaitGroup
    pgsql中json格式数组查询结果变成了字符串
    Go中的unsafe
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/14156986.html
Copyright © 2011-2022 走看看