操作系统面试题总结

操作系统知识点总结

一.概述

1. 什么是操作系统?
  1. 操作系统本质上是一个运行在计算机上的软件程序 ,用于管理计算机硬件和软件资源。
  2. 操作系统存在屏蔽了硬件层的复杂性,为用户和应用程序提供硬件的接口
  3. 操作系统的内核是操作系统的核心部分,它负责系统的内存管理,硬件设备的管理,文件系统的管理以及应用程序的管理
2.什么是系统调用?

根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:

  • 用户态(user mode) : 用户态运行的进程或可以直接读取用户程序的数据。
  • 内核态(kernel mode):可以简单的理解内核态运行的进程或程序几乎可以访问计算机的任何资源,不受限制。

行在用户态下的程序不能直接访问操作系统内核数据结构和程序。
当我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。

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

3. 用户态切换到内核态的3种方式
  • 系统调用: 这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。
  • 异常: 当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
  • 外围设备的中断: 当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
4. 用户栈和内核栈的区别
  1. 当进程运行在内核态时,CPU堆栈指针寄存器指向的是内核堆栈地址,使用的是内核堆栈当进程运行在用户态时。CPU堆栈指针寄存器指向的是用户堆栈地址,使用的是用户堆栈。
    当进程由于中断进入内核态时,系统会把一些用户态的数据信息保存到内核栈中,当返回到用户态时,取出内核栈中得信息恢复出来,返回到程序原来执行的地方。
    用户栈就是进程在用户空间时创建的栈,比如一般的函数调用,将会用到用户栈。
  2. 内核栈是属于操作系统空间的一块固定区域,可以用于保存中断现场、保存操作系统子程序间相互调用的参数、返回值等。
    用户栈是属于用户进程空间的一块区域,用户保存用户进程子程序间的相互调用的参数、返回值等。
  3. 每个Windows 都有4g的进程空间,系统栈使用进程空间的低端部分,用户栈是高端部分。如果用户要直接访问系统栈部分,需要有特殊的方式。

进程用户栈和内核栈之间的切换
当进程由于中断或系统调用从用户态转换到内核态时,进程所使用的栈也要从用户栈切换到内核栈。系统调用实质就是通过指令产生中断,称为软中断。进程因为中断(软中断或硬件产生中断),使得CPU切换到特权工作模式,此时进程陷入内核态,进程进入内核态后,首先把用户态的堆栈地址保存在内核堆栈中,然后设置堆栈指针寄存器的地址为内核栈地址,这样就完成了用户栈向内核栈的切换。

二.进程和线程

$1.什么是进程,什么是线程?

在这里插入图片描述

$2.进程和线程的区别?
  • 进程是资源分配的基本单位,线程是CPU调度的基本单位
  • 进程与线程是不同的系统资源管理方式。进程拥有独立的地址空间,而线程没有
  • 线程不占用系统资源,调度线程比调度进程开销更小,在线程间切换比在进程间切换效率高
  • 线程间的通信比进程间的通信更方便,( 线程共享地址空间,对应的页表是相同的,因此切换线程时,不需要切换页表,TLB等资源,减小了切换开销 )
  • 多进程的程序比多线程程序更加健壮。一个进程崩溃后,在保护模式下,不会对其他进程造成影响;而线程只是进程的一个执行路径,没有自己独立的地址空间,一旦一个线程崩溃,整个进程就会崩溃。
3. 进程有几种状态?状态之间的转换是怎么样的?
  • 创建态 :进程正在被创建,尚未到就绪状态。
  • 就绪态:进程已经获得了除CPU以外的所有所需资源,等待分配CPU资源
  • 运行态:已获得了CPU资源,进行运行。处于运行态的进程数<=CPU核心数
  • 阻塞态:进程等待某些条件,在条件满足前无法执行
  • 结束状态:进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行。
$4.进程间通信的方式有哪些?通信方式的区别
  1. 管道/匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
  2. 有名管道(Names Pipes) : 有名管道可以实现本机任意两个进程通信。
  3. 信号(Signal) :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
  4. 消息队列(Message Queuing) :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。

与管道不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO 更有优势。
消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺陷

  1. 信号量(Semaphores) :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件
  2. 共享内存(Shared memory) :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。共享内存是最快的 IPC方式,可以说这是最有用的进程间通信方式。
  3. 套接字(Sockets) : 此方法主要用于不同机器间的进程通信。。
5.什么是线程同步?

线程同步是指多线程通过特定的方式(如互斥量)来控制线程之间的执行顺序(同步),也可以说是在线程之间通过同步建立起执行顺序的关系,如果没有同步那线程之间是各自运行各自的。

$6.线程同步方式有哪些?
  • 互斥量:每个时刻只有一个线程可以访问公共资源。只有拥有互斥对象的线程才能访问公共资源,互斥对象只有一个,一个时刻只能有一个线程持有,所以保证了公共资源不会被多个线程同时访问。
  • 信号量:允许多个线程同时访问公共资源。但是控制了访问资源的线程的最大个数。
  • 事件 Wait/Notify:通过通知的方式保持多线程的同步,还可以方便的实现多线程优先级的比较
  • 临界区:当多个线程访问一个独占性共享资源时,可以使用临界区对象。拥有临界区的线程可以访问被保护起来的资源或代码段,其他线程若想访问,则被挂起,直到拥有临界区的线程放弃临界区为止。
6.2.互斥量、信号量的区别
  • 互斥量是一种特殊的信号量,对一个互斥量的PV操作都在一个线程中,是一种对临界区的封锁方法。互斥量总是初始化为1。
  • 信号量是线程间通信的一种方法,PV操作在两个线程中,通常由一个线程释放信号量,另一个线程在信号量上排队。初始化值为非负数(0~n)。
  • 互斥量和信号量的原语是一样的。
  1. semWait使信号量减一,若为负数,则此线程阻塞,加入阻塞队列,否则继续执行
  2. semSignal使信号量加一,若<=0,则从信号量的阻塞队列中拿出队首,加入就绪队列
  3. 信号量负数的绝对值n表示了有多少个线程在此信号量上排队,一共n+1个线程,但是只有一个在运行,其余在排队(阻塞队列中)。比如-4表示有4个线程在此信号量上排队。正数的绝对值表示可用资源数,负数的绝对值表示欠缺资源数也表示排队的线程数。
  4. 互斥量的变化范围是 1 ~ -(n-1), n表示共有n个线程尝试访问公共资源
6.5.互斥量和临界区的区别
  • 两者都可以实现对互斥资源的互斥访问
  • 临界区只能用于对象在同一进程里线程间的互斥访问;互斥量可以用于对象进程间或线程间的互斥访问。
  • 临界区是非内核对象,只在用户态进行锁操作,速度快;互斥量是内核对象,在核心态进行锁操作,速度慢。
  • 临界区和互斥体在Windows平台都下可用;Linux下只有互斥体可用。
7.实现临界区的方法有哪些?
  • 软件实现
  • 中断屏蔽(关中断,开中断)
  • 硬件指令方法
$8.线程实现的两种方式?各有什么优缺点?

用户级线程
优点:

  1. 线程切换不需要内核态特权,进程并不需要为了线程管理而切换到内核态
  2. 可以为应用程序量身定做调度算法而不扰乱底层的操作系统调度程序
  3. 用户级线程可以在任何操作系统中运行,不需要对底层内核进行修改以支持用户级线程

缺点:

  1. 许多系统调用都会引起阻塞,当用户级线程执行一个系统调用时,不仅这个线程会被阻塞,进程中的所有线程都会被阻塞
  2. 在纯粹的用户级线程策略中,一个多线程应用程序不能利用多处理技术

内核级线程

该方法克服了用户级线程方法的两个基本缺陷:

  1. 内核可以同时把同一个进程的多个线程调度到多个处理器中;
  2. 如果进程中的一个线程被阻塞,内核可以调度同一个进程中的另一个线程。

相比用户级线程它的主要缺点:

  1. 把控制从一个线程传送到进程中的另一个线程时,需要到内核的状态切换。
9. 进程(线程)调度的几种算法?
  • 先到先服务(FCFS)调度算法 : 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
  • 短作业优先(SJF)的调度算法 : 从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
  • 时间片轮转调度算法(RR) : 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称 RR(Round robin)调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
  • 多级反馈队列调度算法 : 根据优先级分为不同队列,每个队列运行不同的时间片。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。因而它是目前被公认的一种较好的进程调度算法,UNIX 操作系统采取的便是这种调度算法。
  • 优先级调度 : 为每个流程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级。
9.5 多级反馈队列调度算法
  1. 设置多个就绪队列,并为各个队列赋予不同的优先级。在优先权越高的队列中,为每个进程所规定的执行时间片就越小。
  2. 当一个新进程进入内存后,首先放入第一队列的末尾,按FCFS原则排队等候调度。 如果他能在一个时间片中完成,便可撤离;如果未完成,就转入第二队列的末尾,在同样等待调度…… 如此下去,当一个长作业(进程)从第一队列依次将到第n队列(最后队列)后,便按第n队列时间片轮转运行。
  3. 仅当第一队列空闲时,调度程序才调度第二队列中的进程运行;仅当第1到第(i-1)队列空时, 才会调度第i队列中的进程运行,并执行相应的时间片轮转。
  4. 如果处理机正在处理第i队列中某进程,又有新进程进入优先权较高的队列, 则此新队列抢占正在运行的处理机,并把正在运行的进程放在第i队列的队尾。
$10. 进程/线程切换的开销体现在哪些方面

进程切换开销:

  1. 切换页目录以使用新的地址空间
  2. 切换内核栈和硬件上下文

线程切换,第1步是不需要做的

  • 线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。
  • 另外一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,处理的页表缓冲( (TLB))会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题。
11. 进程/线程切换的具体步骤
  1. 保存程序计数以及其他寄存器。
  2. 更新当前处于“运行态”的进程的进程控制块,把进程状态改为相应状态,更新其他相关域
  3. 把被切换进程的进程控制块移到相关状态的队列
  4. 选择另外一个进程开始执行,把该进程进程控制块的状态改为“运行态”
  5. 恢复被选择进程的处理器在最近一次被切换出运行态时的上下文,比如载入程序计数器以及其他处理器的值
12.进程创建的过程?
  1. 给新进程分配一个唯一的标识符
  2. 给进程分配内存空间
  3. 初始化进程控制块PCB
  4. 将PCB放入就绪队列中,等待分配CPU资源
13.什么是进程控制块PCB?
  • 进程存在的唯一标识
  • 创建一个进程就会创建一个PCB,当进程撤销时,系统回收它的PCB
  • 系统对进程的控制根据PCB进行,对进程的管理通过管理PCB实现
  • 能实现间断性的运行方式
  • 提供进程间通信管理所需的资源
  • 提供进程调度所需的信息
14.PCB保存了哪些信息?
  1. 进程的标识信息:如本进程标识,用户标识,父进程标识
  2. CPU和状态信息保存区:如通用寄存器,控制和状态寄存器,栈指针
  3. 进程的控制信息:调度和状态信息,进程间通信信息,存储管理信息,进程所用资源,进程间关系
15. 什么是缓冲区溢出,缓冲区溢出的危害?

当前计算机向缓冲区填充数据时,超出了缓冲区自身的容量,溢出的数据覆盖在合法的数据上。
危害:1.程序崩溃,导致拒绝服务 2.跳转并执行一段恶意代码

16.进程调度和线程调度的关系?
  • 进程和线程都有三种状态(就绪、运行、阻塞)
  • 如果一个线程进行了系统调用,则整个进程阻塞(系统调用会使进程阻塞,而线程还是处于运行态,不会阻塞),控制权从程序转移走,但在线程角度看,此线程还在运行态。而进程已经到了阻塞态。
  • 当线程A等待线程B的某些事件时,A被阻塞,控制权从A移到B。
17. Linux底层是怎么创建线程的

linux中,线程又叫做轻量级进程(light-weight process LWP),也有PCB,创建线程使用的底层函数和进程底层一样,都是clone,但没有独立的地址空间;而进程有独立地址空间,拥有PCB。

实际上,无论是创建进程的fork,还是创建线程的pthread_create,底层实现都是调用同一个内核函数clone。如果复制对方的地址空间,那么就产出一个“进程”;如果共享对方的地址空间,就产生一个“线程”。
因此:Linux内核是不区分进程和线程的。只在用户层面上进行区分。

在这里插入图片描述

18. 僵尸进程

僵尸进程是当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被init接管,子进程退出后init会回收其占用的相关资源

僵尸进程的避免
⒈父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。
⒉ 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。
⒊ 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD,SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。

19. 如果系统中突然出现很多僵尸进程怎么办

系统突然出现大量僵尸进程,肯定是父进程存在问题,这种情况下直接kill掉父进程,使得僵尸进程变成孤儿进程,交由操作系统的init进程进行处理

三.死锁

1.什么是死锁?

在两个以上的并发进程中,如果每个进程都持有某种资源而又等待其他进程释放他们持有的资源,在未改变这种状态前,谁都无法推进,则发生了死锁。所有进程无限期等待,且循环等待,都处于阻塞态。

2.死锁产生的四个必要条件?
  • 互斥。一个资源一次只能被一个进程占有
  • 请求与保持。一个进程因为请求资源而阻塞时,不释放自己持有的资源
  • 非剥夺。无法在进程结束前剥夺它对资源的所有权
  • 循环等待。若干进程收尾相接形成环形等待关系
3.死锁处理的策略?
  • 鸵鸟算法:忽视死锁
  • 预防死锁:破坏后三个条件中的一个即可(互斥是非共享设备的特性,无法更改):

破坏请求与保持条件。规定一个进程开始前,必须申请所有需要的资源。
破坏非剥夺条件。当无法得到需要的资源时,释放自己持有的资源,等需要时再重新申请。
破坏循环等待条件。将所有资源按类型线性排队,并赋予不同的编号,所有进程请求资源时,必须按照资源递增顺序,以防出现环路。如果一个进程已经分配到了R资源,那么它再申请时,只能申请排在R后面的资源,而不能申请前面的资源。

  • 死锁避免:避免死锁并不是事先采取某种限制措施破坏死锁的必要条件,而是再资源动态分配过程中,防止系统进入不安全状态,以避免发生死锁:

在死锁避免中,是否允许当前资源分配请求是通过判断该请求是否可能导致死锁来决定的。因此,死锁避免需要知道将来的进程资源请求的情况。死锁避免策略并不能确切的预测死锁,它仅仅是预测死锁的可能性并确保永远不会出现这种可能性。

有两种死锁避免的办法:
如果一个进程的请求会导致死锁,则不启动此进程
如果一个进程增加的资源请求会导致死锁,则不允许这次分配

银行家算法 系统安全状态 安全性算法

  • 死锁的检测与解除

资源分配图 死锁定理 死锁解除

四.内存管理

1. 操作系统的内存管理主要是做什么?

操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),将逻辑地址转换成相应的物理地址等。

2. 什么是物理地址?什么是逻辑地址?区别与联系?
  • 我们编程一般只有可能和逻辑地址打交道,比如在 C 语言中,指针里面存储的数值就可以理解成为内存里的一个地址,这个地址也就是我们说的逻辑地址,逻辑地址由操作系统决定。
  • 物理地址指的是真实物理内存中地址,更具体一点来说就是内存地址寄存器中的地址。物理地址是内存单元真正的地址
    在这里插入图片描述
3. 虚拟地址空间存在的意义?

没有虚拟地址空间的时候,程序都是直接访问和操作的都是物理内存 。但是这样有什么问题呢?

  1. 用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易(有意或者无意)破坏操作系统,造成操作系统崩溃
  2. 想要同时运行多个程序特别困难,比如你想同时运行一个微信和一个 QQ 音乐都不行。为什么呢?举个简单的例子:微信在运行的时候给内存地址 1xxx 赋值后,QQ 音乐也同样给内存地址 1xxx 赋值,那么 QQ 音乐对内存的赋值就会覆盖微信之前所赋的值,这就造成了微信这个程序就会崩溃。

总结来说:如果直接把物理地址暴露出来的话会带来严重问题,比如可能对操作系统造成伤害以及给同时运行多个程序造成困难。

通过使用虚拟地址空间:

  • 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区
  • 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区
  • 不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。
4.CPU寻址

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

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

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

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

共同点 :

  • 分页机制和分段机制都是为了提高内存利用率,较少内存碎片
  • 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。

区别 :

  • 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
  • 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
7.快表和多级页表

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

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

快表

为了解决虚拟地址到物理地址的转换速度,操作系统在 页表方案 基础之上引入了 快表 来加速虚拟地址到物理地址的转换。我们可以把快表理解为一种特殊的高速缓冲存储器(Cache),其中的内容是页表的一部分或者全部内容。作为页表的 Cache,它的作用与页表相似,但是提高了访问速率。由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。

使用快表之后的地址转换流程是这样的:

  1. 根据虚拟地址中的页号查快表;
  2. 如果该页在快表中,直接从快表中读取相应的物理地址;
  3. 如果该页不在快表中,就访问内存中的页表,再从页表中得到物理地址,同时将页表中的该映射表项添加到快表中;
  4. 当快表填满后,又要登记新页时,就按照一定的淘汰策略淘汰掉快表中的一个页。

多级页表

引入多级页表的主要目的是为了避免把全部页表一直放在内存中占用过多空间,特别是那些根本就不需要的页表就不需要保留在内存中。多级页表属于时间换空间的典型场景,具体可以查看下面这篇文章

多级页表如何节约内存:https://www.polarxiong.com/archives/多级页表如何节约内存.html

8. 虚拟内存

很多时候我们使用点开了很多占内存的软件,这些软件占用的内存可能已经远远超出了我们电脑本身具有的物理内存。 正是因为 虚拟内存 的存在,

通过 虚拟内存把内存扩展到硬盘空间,可以让程序可以拥有超过系统物理内存大小的可用内存空间。

另外,虚拟内存为每个进程提供了一个一致的、私有的地址空间,它让每个进程产生了一种自己在独享主存的错觉(每个进程拥有一片连续完整的内存空间)。这样会更加有效地管理内存并减少出错。

8.5 Swap分区

Swap分区在系统的物理内存不够用的时候,把硬盘内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap分区中,等到那些程序要运行时,再从Swap分区中恢复保存的数据到内存中。

9. 局部性原理

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

局部性原理表现在以下两个方面:

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

时间局部性是通过将近来使用的指令和数据保存到高速缓存存储器中,并使用高速缓存的层次结构实现。空间局部性通常是使用较大的高速缓存,并将预取机制集成到高速缓存控制逻辑中实现。虚拟内存技术实际上就是建立了 “内存一外存”的两级存储器的结构,利用局部性原理实现髙速缓存。

10. 虚拟存储器

基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其他部分留在外存,就可以启动程序执行。由于外存往往比内存大很多,所以我们运行的软件的内存大小实际上是可以比计算机系统实际的内存大小大的。
在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换到外存上,从而腾出空间存放将要调入内存的信息。这样,计算机好像为用户提供了一个比实际内存大的多的存储器——虚拟存储器。

11. 虚拟内存技术的实现呢?

虚拟内存的实现需要建立在离散分配的内存管理方式的基础上。 虚拟内存的实现有以下三种方式:

  • 请求分页存储管理 :建立在分页管理之上,为了支持虚拟存储器功能而增加了请求调页功能和页面置换功能。请求分页是目前最常用的一种实现虚拟存储器的方法。请求分页存储管理系统中,在作业开始运行之前,仅装入当前要执行的部分段即可运行。假如在作业运行的过程中发现要访问的页面不在内存,则由处理器通知操作系统按照对应的页面置换算法将相应的页面调入到主存,同时操作系统也可以将暂时不用的页面置换到外存中。(页表中有是在内存还是在外存的标志位)
  • 请求分段存储管理 :建立在分段存储管理之上,增加了请求调段功能、分段置换功能。请求分段储存管理方式就如同请求分页储存管理方式一样,在作业开始运行之前,仅装入当前要执行的部分段即可运行;在执行过程中,可使用请求调入中断动态装入要访问但又不在内存的程序段;当内存空间已满,而又需要装入新的段时,根据置换功能适当调出某个段,以便腾出空间而装入新的段。
  • 请求段页式存储管理
12. 请求分页与分页存储管理,两者有何不同呢?

请求分页存储管理建立在分页管理之上。他们的根本区别是是否将程序全部所需的全部地址空间都装入主存,这也是请求分页存储管理可以提供虚拟内存的原因,我们在上面已经分析过了。

它们之间的根本区别在于是否将一作业的全部地址空间同时装入主存。请求分页存储管理不要求将作业全部地址空间同时装入主存。基于这一点,请求分页存储管理可以提供虚存,而分页存储管理却不能提供虚存。

13. 页面置换算法

当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一页的规则叫做页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。

  • OPT 页面置换算法(最佳页面置换算法) :最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法
  • FIFO(First In First Out) 页面置换算法(先进先出页面置换算法) : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
  • LRU (Least Currently Used)页面置换算法(最近最久未使用页面置换算法) :LRU算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 T,当须淘汰一个页面时,选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。
  • LFU (Least Frequently Used)页面置换算法(最少使用页面置换算法) : 该置换算法选择在之前时期使用最少的页面作为淘汰页。
  • 时钟页面置换算法
  • NRU 最近未使用页面置换算法
  • 二次机会算法(FIFO的改进)
14. 内存连续分配方式采用的空闲内存分配的三个适配算法?
  • 最佳适配:选择与需求大小最接近的块。为了加速查找,该算法需求将所有的空闲区按其大小排序后,以递增顺序形成一个空白链。这样每次找到的第一个满足需求的空闲区,必然是最优的。孤立地看,该算法似乎是最优的,但事实上并不一定。因为每次分配后剩余的空间一定是最小的,缺点是在存储器中将留下许多难以利用的小空闲区。同时每次分配后必须重新排序,这也带来了一定的开销
  • 首次适配:从第一个开始,选择第一个满足大小的空闲块。缺点在于低址部分不断被划分,留下许多难以利用、非常小的空闲区,而每次查找又都从低址部分开始,这无疑会增加查找的开销
  • 最差适配:选择最大的空闲块。该算法克服了最佳适应算法留下的许多小的碎片的不足,但缺点是保留大的空闲区的可能性减小了,而且空闲区回收也和最佳适应算法相同复杂。
  • 快速适配:为常用的空闲区维护单独的链表,便于快速找到相应大小空闲区
15. malloc实现原理
  1. 可以基于伙伴系统实现,也可以使用基于链表的实现
  2. 将所有空闲内存块连成链表,每个节点记录空闲内存块的地址、大小等信息
  3. 分配内存时,找到大小合适的块,切成两份,一分给用户,一份放回空闲链表
  4. free时,直接把内存块返回链表
  5. 解决外部碎片:将能够合并的内存块进行合并
16. 使用mmap读写文件为什么比普通读写函数要快?

mmap函数:可以将文件映射到内存中的一段区域,
普通函数读写文件:用户空间buffer内核空间buffer磁盘;mmap映射之后:用户空间buffer进程内存空间,省掉了拷贝到内核空间的时间?

17. 伙伴系统,内存是怎么申请的

在实际应用中,经常需要分配一组连续的页框,而频繁地申请和释放不同大小的连续页框,必然导致在已分配页框的内存块中分散了许多小块的空闲页框。这样,即使这些页框是空闲的,其他需要分配连续页框的应用也很难得到满足。

为了避免出现这种情况,Linux内核中引入了伙伴系统算法(buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。

假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个页框的链表中找,找到了则将页框块分为2个256个页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页框的链表查找,如果仍然没有,则返回错误。

页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。

五、I/O管理和文件系统

1. I/O软件的四个层次

分别是:用户级I/O软件、设备无关软件、设备驱动程序、中断处理程序。

2. 什么是文件描述符
  • 先说files,它是一个文件指针数组。一般来说,一个进程会从files[0]读取输入,将输出写入files[1],将错误信息写入files[2]。
  • 每个进程被创建时,files的前三位被填入默认值,分别指向标准输入流、标准输出流、标准错误流。我们常说的「文件描述符」就是指这个文件指针数组的索引,所以程序的文件描述符默认情况下 0 是输入,1 是输出,2 是错误
    在这里插入图片描述
  1. 明白了这个原理,输入重定向就很好理解了,程序想读取数据的时候就会去files[0]读取,所以我们只要把files[0]指向一个文件,那么程序就会从这个文件中读取数据,而不是从键盘:
  2. 管道符其实也是异曲同工,把一个进程的输出流和另一个进程的输入流接起一条「管道」,数据就在其中传递
3. 中断机制

由用户态切换到内核态本质是通过中断机制实现的,中断机制的步骤:

  1. 从当前进程的描述符中提取其内核栈的ss0及esp0信息。
  2. 使用ss0和esp0指向的内核栈将当前进程的cs,eip,eflags,ss,esp信息保存起来,这个过程也完成了由用户栈到内核栈的切换过程,同时保存了被暂停执行的程序的下一条指令。
  3. 将先前由中断向量检索得到的中断处理程序的cs,eip信息装入相应的寄存器,开始执行中断处理程序,这时就转到了内核态的程序执行了。
4. 磁盘调度算法
  1. 先来先服务算法(FCFS)
    这是一种比较简单的磁盘调度算法。它根据进程请求访问磁盘的先后次序进行调度。此算法的优点是公平、简单,且每个进程的请求都能依次得到处理,不会出现某一进程的请求长期得不到满足的情况。此算法由于未对寻道进行优化,在对磁盘的访问请求比较多的情况下,此算法将降低设备服务的吞吐量,致使平均寻道时间可能较长,但各进程得到服务的响应时间的变化幅度较小。
  2. 最短寻道时间优先算法(SSTF) Shortest Seek Time First
    该算法选择这样的进程,其要求访问的磁道与当前磁头所在的磁道距离最近,以使每次的寻道时间最短,该算法可以得到比较好的吞吐量,但却不能保证平均寻道时间最短。其缺点是对用户的服务请求的响应机会不是均等的,因而导致响应时间的变化幅度很大。在服务请求很多的情况下,对内外边缘磁道的请求将会无限期的被延迟,有些请求的响应时间将不可预期。
  3. 扫描算法(SCAN)电梯调度
    扫描算法不仅考虑到欲访问的磁道与当前磁道的距离,更优先考虑的是磁头的当前移动方向。例如,当磁头正在自里向外移动时,扫描算法所选择的下一个访问对象应是其欲访问的磁道既在当前磁道之外,又是距离最近的。这样自里向外地访问,直到再无更外的磁道需要访问才将磁臂换向,自外向里移动。这时,同样也是每次选择这样的进程来调度,即其要访问的磁道,在当前磁道之内,从而避免了饥饿现象的出现。由于这种算法中磁头移动的规律颇似电梯的运行,故又称为电梯调度算法。此算法基本上克服了最短寻道时间优先算法的服务集中于中间磁道和响应时间变化比较大的缺点,而具有最短寻道时间优先算法的优点即吞吐量较大,平均响应时间较小,但由于是摆动式的扫描方法,两侧磁道被访问的频率仍低于中间磁道。
  4. 循环扫描算法(CSCAN)
    循环扫描算法是对扫描算法的改进。如果对磁道的访问请求是均匀分布的,当磁头到达磁盘的一端,并反向运动时落在磁头之后的访问请求相对较少。这是由于这些磁道刚被处理,而磁盘另一端的请求密度相当高,且这些访问请求等待的时间较长,为了解决这种情况,循环扫描算法规定磁头单向移动。例如,只自里向外移动,当磁头移到最外的被访问磁道时,磁头立即返回到最里的欲访磁道,即将最小磁道号紧接着最大磁道号构成循环,进行扫描。
5. 硬链接和软链接
  1. 硬链接就是同一个文件使用了多个别名(他们有共同的 inode)。
    软链接(也叫符号链接)与硬链接不同,文件用户数据块中存放的内容是另一文件的路径名的指向。软链接就是一个普通文件,只是数据块内容有点特殊。

  2. 由于硬链接是有着相同 inode 号仅文件名不同的文件,因此,删除一个硬链接文件并不影响其他有相同 inode 号的文件。
    删除软链接并不影响被指向的文件,但若被指向的原文件被删除,则相关软连接就变成了死链接。

  3. 硬链接不能对目录进行创建,只可对文件创建。
    软链接可对文件或目录创建。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值