面试准备:操作系统常见面试题汇总

文章目录

  • 1.为什么要有用户态和内核态?内核态和用户态的运作方式?
  • 2.进程间通信方式介绍
  • 3.Linux查看进程状态、cpu状态、占用端口的进程号的命令?linux top命令VIRT,RES,SHR,DATA的含义?
  • 4.什么是Swap?
  • 5.什么是上下文切换?
  • 6.为什么进程上下文切换比线程上下文切换代价高?
  • 7.进程调度
  • 8.逻辑地址 Vs 物理地址 Vs 虚拟内存
  • 9.内部碎片与外部碎片
  • 10.同步和互斥的区别
  • 11.CPU缓存?
  • 12. 为什么要使用多线程呢?
  • 13. 什么是操作系统OS?
  • 14. 什么是系统调用?
  • 15. 线程间的同步的方式?
  • 16. 常见的几种内存管理机制?
  • 17. 简单描述快表和多级页表?
  • 18. CPU 寻址了解吗?
  • 19. 为什么要有虚拟(逻辑)地址空间呢?
  • 20. 局部性原理?
  • 21.页面置换算法?
  • 22. 了解一下Linux文件系统

1.为什么要有用户态和内核态?内核态和用户态的运作方式?

由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级——用户态和内核态。这两种状态的主要差别在于:进程所能访问的内存空间和资源是否受到限制。

用户态切换到内核态的3种方式:

  1. 系统调用。用户态进程主动要求切换到内核态来申请使用操作系统提供的服务程序完成工作。
  2. 异常。当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常
  3. 外围设备的中断。当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序。

所有用户程序都是运行在用户态的, 但是有时候程序确实需要做一些内核态的事情, 例如从硬盘读取数据, 或者从键盘获取输入等。这时候需要将用户态切换为内核态,这种机制叫系统调用, 在CPU中的实现称之为陷阱指令(Trap Instruction)。系统调用过程如下:

  1. 用户态程序将一些数据放在寄存器或者堆栈(stack frame)里,以此表明需要操作系统提供的服务。
  2. 用户态程序执行陷阱指令,CPU切换到内核态。
  3. 之后,会读取程序放入内存的数据参数, 并执行程序请求的服务。
  4. 系统调用完成后, 操作系统会重置CPU为用户态并返回系统调用的结果。

2.进程间通信方式介绍

  • 共享内存:
    顾名思义,共享内存就是两个进程同时共享一块内存,然后在这块内存上的数据可以共同修改和读取,达到通信的目的;共享内存是最快的ipc方式;共享内存常与信号量进行配合使用

  • 信号量:
    信号量是一个控制资源访问的标识符 (简单来说就是一个计数器),具有原子性,主要是用来做PV操作,实现进程间同步。

PV操作是一种实现进程互斥与同步的有效方法。PV操作与信号量的处理相关,P表示通过的意思,V表示释放的意思。

  • 无名管道(Pipe):
    无名管道是在具有亲缘关系的进程之间的一种ipc方式,亲缘关系是指fork出的父子进程、兄弟进程这样一个关系,他们创建的时候会同时持有一个无名管道的句柄,句柄存在于内存之中,具有一个读端和写端,进程之间可以通过句柄来进行半双工的通信。

句柄可以简单理解为数据:fd[0],fd[1],也就是两个分别用来读和写的文件描述符。
父子进程:通过fork函数创建的新进程是原进程的子进程。
兄弟进程:同一个进程多次fork产生的子进程之间互为兄弟进程。

  • 命名管道(FIFO):
    命名管道相比于无名管道,虽然也是半双工的通信方式,但是可以在不具有亲缘关系的进程间通信:凡是可以访问到磁盘上对应路径的FIFO文件的进程都可以通信。

FIFO文件是一种特殊设备的文件形式,在文件系统中可以看到。程序中可以查看文件stat结构中st_mode成员的值来判断文件是否是FIFO文件。

  • 消息队列:
    消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息不一定要以先进先出的次序读取,可以实现随机查询。消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

  • 套接字(Socket):
    套接字是网络编程的api,通过套接字可以不同的机器间的进程进行通信,常用于客户端进程和服务器进程的通信。

3.Linux查看进程状态、cpu状态、占用端口的进程号的命令?linux top命令VIRT,RES,SHR,DATA的含义?

查看进程状态ps -ef

查看cpu状态 top
Cpu(s):
0.1%us 用户空间占用CPU百分比
0.0%sy 内核空间占用CPU百分比
0.0%ni 用户进程空间内改变过优先级的进程占用CPU百分比
99.9%id 空闲CPU百分比

查看占用端口的进程号netstat -an|grep
查看内存:free -m


VIRT:virtual memory usage 虚拟内存
1、进程“需要的”虚拟内存大小,包括进程使用的库、代码、数据等
2、假如进程申请100m的内存,但实际只使用了10m,那么它会增长100m,而不是实际的使用量

RES:resident memory usage 常驻内存
1、进程当前使用的内存大小,但不包括swap out
2、包含其他进程的共享
3、如果申请100m的内存,实际使用10m,它只增长10m,与VIRT相反
4、关于库占用内存的情况,它只统计加载的库文件所占内存大小

SHR:shared memory 共享内存
1、除了自身进程的共享内存,也包括其他进程的共享内存
2、虽然进程只使用了几个共享库的函数,但它包含了整个共享库的大小
3、计算某个进程所占的物理内存大小公式:RES – SHR
4、swap out后,它将会降下来

DATA
1、数据占用的内存。如果top没有显示,按f键可以显示出来。
2、真正的该程序要求的数据空间,是真正在运行中要使用的。

4.什么是Swap?

从功能上讲,交换分区主要是在内存不够用的时候,将部分内存上的数据交换到swap空间上,以便让系统不会因内存不够用而导致oom或者更致命的情况出现。swap空间是磁盘上的一块区域,可以是一个分区,也可以是一个文件,或者是他们的组合。

在Linux上可以使用swapon -s命令查看当前系统上正在使用的交换空间有哪些。

5.什么是上下文切换?

对于单核单线程CPU而言,在某一时刻只能执行一条CPU指令。

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

6.为什么进程上下文切换比线程上下文切换代价高?

进程切换分两步:

1.切换页目录以使用新的地址空间。(每一个进程拥有自己独立的内存空间,而线程共享进程的内存空间。)

每个进程有自己的页目录和页表,所以每个进程的地址空间映射的物理内存是不一样的。

2.切换内核栈和硬件上下文

内核在创建进程的时候,会为进程创建相应的堆栈。每一个进程都有两个栈,一个用户栈,存在于用户空间;一个内核栈,存在于内核空间。当进程在用户空间运行时,CPU堆栈指针寄存器里面的内容都是用户栈地址,使用用户栈;当进程在内核空间时,CPU堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。
当进程因为中断或者系统调用陷入到内核态时,进程所使用的堆栈也要从用户栈转到内核栈。进程陷入到内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完成了用户栈向内核栈的转换当进程从内核态恢复到用户态之后时,在内核态之后的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器即可。

尽管每个进程可以拥有属于自己的地址空间,但是所有进程必须共享CPU寄存器,因此,在恢复一个进程的执行前,内核必须确保每个寄存器装入了挂起进程时的值。
进程恢复执行前必须装入寄存器的那一组数据成为硬件上下文。

对于linux来说,线程和进程的最大区别就在于地址空间,对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的。

7.进程调度

  • 调度种类

高级调度:(High-Level Scheduling)又称为作业调度,它决定把后备作业调入内存运行;

低级调度:(Low-Level Scheduling)又称为进程调度,它决定把就绪队列的某进程获得CPU;

中级调度:(Intermediate-Level Scheduling)又称为在虚拟存储器中引入,在内、外存对换区进行进程对换。

  • 非抢占式调度与抢占式调度

非抢占式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生进程调度进程调度某事件而阻塞时,才把处理机分配给另一个进程。

抢占式:操作系统将正在运行的进程强行暂停,由调度程序将CPU分配给其他就绪进程的调度方式。

  • 调度策略的设计

响应时间: 从用户输入到产生反应的时间

周转时间: 从任务开始到任务结束的时间

CPU任务可以分为交互式任务和批处理任务,调度最终的目标是合理的使用CPU,使得交互式任务的响应时间尽可能短,用户不至于感到延迟,同时使得批处理任务的周转时间尽可能短,减少用户等待的时间。

  • 调度算法:

    1. FIFO或First Come, First Served (FCFS)先来先服务
      调度的顺序就是任务到达就绪队列的顺序。
      公平、简单(FIFO队列)、非抢占、不适合交互式。
      未考虑任务特性,平均等待时间可以缩短。

    2. 优先权调度
      每个任务关联一个优先权,调度优先权最高的任务。
      注意:优先权太低的任务一直就绪,得不到运行,出现“饥饿”现象。

    3. Shortest Job First (SJF)
      最短的作业(CPU区间长度最小)最先调度。
      SJF可以保证最小的平均等待时间。

    4. Shortest Remaining Job First (SRJF)
      SJF的可抢占版本,比SJF更有优势。

    5. Round-Robin(RR)时间片轮转
      设置一个时间片,按时间片来轮转调度。
      优点: 定时有响应,等待时间较短;缺点: 上下文切换次数较多;
      时间片太大,响应时间太长;吞吐量变小,周转时间变长;当时间片过长时,退化为FCFS。

    6. 多级队列调度
      按照一定的规则建立多个进程队列
      不同的队列有固定的优先级(高优先级有抢占权)
      不同的队列可以给不同的时间片和采用不同的调度方法
      存在问题1:没法区分I/O bound和CPU bound;
      存在问题2:也存在一定程度的“饥饿”现象;

    7. 多级反馈队列
      在多级队列的基础上,任务可以在队列之间移动,更细致的区分任务。
      可以根据“享用”CPU时间多少来移动队列,阻止“饥饿”。
      最通用的调度算法,多数OS都使用该方法或其变形,如UNIX、Windows等。

8.逻辑地址 Vs 物理地址 Vs 虚拟内存

所谓的逻辑地址,是指计算机用户(例如程序开发者),看到的地址。
例如,当创建一个长度为100的整型数组时,操作系统返回一个逻辑上的连续空间指针指向数组第一个元素的内存地址。由于整型元素的大小为4个字节,故第二个元素的地址时起始地址加4,以此类推。事实上,逻辑地址并不一定是元素存储的真实地址,即数组元素的物理地址(在内存条中所处的位置),并非是连续的,只是操作系统通过地址映射,将逻辑地址映射成连续的,这样更符合人们的直观思维。

虚拟内存 使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

9.内部碎片与外部碎片

在内存管理中,内部碎片是已经被分配出去的的内存空间大于请求所需的内存空间。

外部碎片是指还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。

页式虚拟存储系统存在内部碎片;段式虚拟存储系统,存在外部碎片

为了有效的利用内存,使内存产生更少的碎片,要对内存分页,内存以页为单位来使用,最后一页往往装不满,于是形成了内部碎片。

为了共享要分段,在段的换入换出时形成外部碎片,比如5K的段换出后,有一个4k的段进来放到原来5k的地方,于是形成1k的外部碎片。

10.同步和互斥的区别

同步,是指散步在不同进程之间的若干程序片断,它们的运行必须严格按照规定的某种先后次序来运行,这种先后次序依赖于要完成的特定的任务。如果用对资源的访问来定义的话,同步是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。

所谓互斥,是指散布在不同进程之间的若干程序片断,当某个进程运行其中一个程序片段时,其它进程就不能运行它们之中的任一程序片段,只能等到该进程运行完这个程序片段后才可以运行。如果用对资源的访问来定义的话,互斥某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。

11.CPU缓存?

CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器,它的容量比内存小的多但是交换速度却比内存要快得多。
缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾。当CPU调用大量数据时,就可避开内存直接从缓存中调用,从而加快读取速度。

缓存的工作原理是当CPU要读取一个数据时,首先从缓存中查找,如果找到就立即读取并送给CPU处理;如果没有找到,就用相对慢的速度从内存中读取并送给CPU处理,同时把这个数据所在的数据块调入缓存中,可以使得以后对整块数据的读取都从缓存中进行,不必再调用内存。

按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存,二级缓存,部分高端CPU还具有三级缓存,每一级缓存中所储存的全部数据都是下一级缓存的一部分,这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。

12. 为什么要使用多线程呢?

  1. 避免阻塞(异步调用)
    线程在运行之中,比如遇到磁盘IO、RPC等这些比CPU处理慢得多的操作,就需要阻塞、自旋,这一段时间可以用来运行其它线程的任务,提高效率。
  2. 多核处理器
    现在的处理器几乎都是多核的,一个单线程程序在运行时只能使用一个处理器核心。

13. 什么是操作系统OS?

操作系统本质上是在硬件上运行的软件系统,用于管理计算机硬件与软件资源的程序。
它可以的简单的分为两个部分,外壳和内核。外壳负责与用户进行交互,内核负责与硬件进行交互。

14. 什么是系统调用?

我们运行的程序基本都是运行在用户态,如果我们调用操作系统提供的系统态级别的子功能咋办呢?那就需要系统调用了!

也就是说在我们运行的用户程序中,凡是与系统态级别的资源有关的操作(如文件管理、进程控制、内存管理等),都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。

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

设备管理。完成设备的请求或释放,以及设备启动等功能。
文件管理。完成文件的读、写、创建及删除等功能。
进程控制。完成进程的创建、撤销、阻塞及唤醒等功能。
进程通信。完成进程之间的消息传递或信号传递等功能。
内存管理。完成内存的分配、回收以及获取作业占用内存区大小及地址等功能。

15. 线程间的同步的方式?

  • 共享内存:
    1. 互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
    2. 信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
    3. 事件(Event) :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较
  • 消息队列:
    1. 管道(Pipe):Java提供管道功能,实现管道通信的类有两组:PipedInputStream和PipedOutputStream或者是PipedReader和PipedWriter。

16. 常见的几种内存管理机制?

简单分为连续分配管理方式非连续分配管理方式这两种。连续分配管理方式是指为一个用户程序分配一个连续的内存空间,常见的如 块式管理 。同样地,非连续分配管理方式允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理段式管理

  • 块式管理 : 远古时代的计算机操系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片。
  • 页式管理 :把主存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
  • 段式管理 : 页式管理虽然提高了内存利用率,但是页式管理其中的页实际并无任何实际意义。 段式管理把主存分为一段段的,每一段的空间又要比一页的空间小很多 。但是,最重要的是段是有实际意义的每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址。
  • 段页式管理:段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。

分页机制和分段机制的共同点和区别?

  • 共同点 :
    1. 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
    2. 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
  • 区别 :
    1. 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
    2. 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。

17. 简单描述快表和多级页表?

在分页内存管理中,很重要的两点是:

  1. 虚拟地址(逻辑地址)到物理地址的转换要快。
  2. 解决虚拟地址空间大,页表也会很大的问题。

为了提高内存的空间性能,提出了多级页表的概念;但是提到空间性能是以浪费时间性能为基础的,因此为了补充损失的时间性能,提出了快表(即 TLB)的概念。

快表(TLB):
也叫旁路转换缓冲或者页表缓冲,可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的 Cache,它的作用与页表相似。如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。

多级页表:
引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。给进程分配的内存空间很大的话,对应页表也很大。于是就要建立多级页表,把高层页表(相对级别比较高的)放在内存,靠这个高层页表找底层页表,再在底层页表里找到对应的实页号。部分底层页表在内存,另外的一些就被塞在磁盘,被高层页表点名之后,才调入内存

18. CPU 寻址了解吗?

CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。 实际上完成虚拟地址转换为物理地址转换的硬件是 CPU 中含有一个被称为 内存管理单元(Memory Management Unit, MMU) 的硬件

CPU要寻址的时候,就会将虚拟地址告知给MMU,然后MMU在快表TLB中查询真实的物理地址,如果没有命中,还要去到磁盘中寻找,如下图所示:
面试准备:操作系统常见面试题汇总_第1张图片

19. 为什么要有虚拟(逻辑)地址空间呢?

  1. 避免多个程序之间的物理地址冲突:主要是因为,如果程序直接写入物理地址的话,就需要使用得到该物理地址,而如果该物理地址已经被占用了,就会发生冲突。所以使用虚拟地址映射到物理地址,可以避免物理地址的冲突。
  2. 屏蔽底层内存访问:用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易(有意或者无意)破坏操作系统,造成操作系统崩溃。
  3. 程序可以使用一系列相邻的虚拟地址来访问内存中不相邻的物理地址

20. 局部性原理?

局部性原理是虚拟内存技术的基础,正是因为程序运行具有局部性原理,才可以只装入部分程序到内存就开始运行。

局部性原理的主要内容就是:

  1. 时间局部性 :如果程序中的某条指令一旦执行,不久以后该指令可能再次执行;如果某数据被访问过,不久以后该数据可能再次被访问。产生时间局部性的典型原因,是由于在程序中存在着大量的循环操作。
  2. 空间局部性 :一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也将被访问,即程序在一段时间内所访问的地址,可能集中在一定的范围之内,这是因为指令通常是顺序存放、顺序执行的,数据也一般是以向量、数组、表等形式簇聚存储的。

21.页面置换算法?

  • OPT 页面置换算法(最佳页面置换算法)

最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法。

  • FIFO(First In First Out) 先进先出页面置换算法 :

总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。

  • LRU (Least Currently Used)最近最久未使用页面置换算法:

LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 T,当须淘汰一个页面时,选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。

  • LFU (Least Frequently Used) 最少使用页面置换算法

最少使用页面置换算法 : 该置换算法选择在之前时期使用最少的页面作为淘汰页。

22. 了解一下Linux文件系统

参考:Linux文件系统概要

你可能感兴趣的:(面试准备)