操作系统涉及到的算法 | 进程调度 | 页面置换算法 | 磁盘调度算法 | 内存分配算法

290 阅读13分钟

进程调度

调度算法其实只会影响作业/进程的等待时间。

非抢占式调度:当进程正在运行时,它就会一直运行,直到该进程完成或发生某个事件而被阻塞时,才会把 CPU 让给其他进程。

非抢占式调度有,先来先服务算法、高响应比优先(HRRN)

抢占式调度:进程正在运行的时,可以被打断,使其把 CPU 让给其他进程。

抢占式调度有,时间片原则、优先权原则、短作业优先原则。

既可以是抢占式也可以是非抢占式,SJF和SPF是非抢占式的算法。但是也有抢占式的版本--最短剩余时间优先算法(SRTRN, Shortest Remaining Time Next )

先来先服务(FCFS)

按照进程到达的先后顺序进行服务

  • 优缺点
  •   优点:算法实现简单
  •   缺点:排在长作业(进程)后面的短作业需要等待很长时间,带权周转时间很大,对短作业来说用户体验不好。即,FCFS算法对长作业有利,对短作业不利(Eg: 排队买奶茶... )

短作业优先(SPF)

优先选择运行时间最短的进程来运行,这有助于提高系统的吞吐量。

  • 优缺点
  •   优点:“最短的”平均等待时间、平均周转时间
  •   缺点:不公平。对短作业有利,对长作业不利。可能产生饥饿现象。另外,作业/进程的运行时间是由用户提供的,并不一定真实,不一定能做到真正的短作业优先

高响应比优先(HRRN)

由于先来先服务算法和短作业优先算法都没有很好的平衡短作业和长作业,所以利用高相应比优先算法去解决

在每次调度时先计算各个作业/进程的响应比,选择响应比最高的作业/进程为其服务

公式:优先权=(等待时间+要求服务时间)/(要求服务时间)

优点

  • 综合考虑了等待时间和运行时间(要求服务时间)
  • 等待时间相同时,要求服务时间短的优先(SJF 的优点)
  • 要求服务时间相同时,等待时间长的优先(FCFS 的优点)
  • 对于长作业来说,随着等待时间越来越久,其响应比也会越来越大,从而避免了长作业饥饿的问题

时间片轮转( RR, Round-Robin)

公平地、轮流地为各个进程服务,让每个进程在一定时间间隔内都可以得到响应

  • 优缺点

  •   优点:公平,响应快,适用于分时操作系统

  •   缺点:高频率的进程切换有一定的开销,不区分任务的紧急程度

时间片大小

如果时间片太大,使得每个进程都可以在一个时间片内就完成,则时间片轮转调度算法退化为先来先服务调度算法,并且会增大进程响应时间。因此时间片不能太大。

时间片太小,会导致进程切换过于频繁,系统会花大量的时间来处理进程切换,从而导致实际用于进程执行的时间比例减少。可见时间片也不能太小。

优先级调度算法

每个作业/进程有各自的优先级,调度时选择优先级最高的作业/进程

  • 优缺点
  •   优点:用优先级区分紧急程度、重要程度,适用于实时操作系统。可灵活地调整对各种作业/进程的偏好程度
  •   缺点:若源源不断地有高优先级进程到来,则可能导致饥饿

如何设置合理的优先级?

系统进程优先级高于用户进程

前台用户优先级高于后台进程

操作系统更偏好I/O型进程

多级反馈队列调度算法

  • 算法规则
  •   设置多级就绪队列调度,各级队列优先级从高到低,时间片从小到大
  •   新进程到达时先进入第1级队列,按FCFS原则排队等待被分配时间片,若用完时间片进程还未结束,则进程进入下一级队列队尾。如果此时已经是在最下级的队列,则重新放回该队列队尾
  •   只有第k级队列为空时,才会为k+1级队头的进程分配时间片
  • 优缺点
  •   优点
  •     对各类型进程相对公平(FCFS的优点) ;
  •     每个新到达的进程都可以很快就得到响应(RR的优点);
  •     短进程只用较少的时间就可完成(SPF的优点) ;
  •     不必实现估计进程的运行时间( 避免用户作假) ;
  •     可灵活地调整对各类进程的偏好程度,比如CPU密集型进程、I/O密集型进程(拓展:可以将因I/O而阻塞的进程重新放回原队列,这样I/O型进程就可以保持较高优先级)
  •   缺点:会导致饥饿

页面置换算法

用页面置换算法决定应该换出哪个页面

页面的换入、换出需要磁盘1/O,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率

缺页异常:当 CPU 访问的页面不在物理内存时,便会产生一个缺页中断,请求操作系统将所缺页调入到物理内存。

最佳置换算法(OPT)

每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。

实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面访问序列。因此,最佳置换算法是无法实现的。

先进先出置换算法(FIFO)

每次选择淘汰的页面是最早进入内存的页面

实现:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。队列的最大长度取决于系统为进程分配了多少个内存块

Belady异常: 当为进程分配的物理块数增大时,缺页次数不减反增的异常现象

只有FIFO算法会产生Belady异常。另外,FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应,因为先进入的页面也有可能最经常被访问。因此,算法性能差

最近最久未使用置换算法(LRU)

选择最长时间没有被访问的页面进行置换

该算法假设已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。

虽然 LRU 在理论上是可以实现的,但代价很高。为了完全实现 LRU,需要在内存中维护一个所有页面的链表,最近最多使用的页面在表头,最近最少使用的页面在表尾。

困难的是,在每次访问内存时都必须要更新「整个链表」。在链表中找到一个页面,删除它,然后把它移动到表头是一个非常费时的操作。

所以,LRU 虽然看上去不错,但是由于开销比较大,实际应用中比较少使用。

时钟置换算法(CLOCK)

时钟置换算法是一种性能和开销较均衡的算法,又称CLOCK算法,或最近未用算法(NRU,Not Recently Used )

该算法的思路是,把所有的页面都保存在一个类似钟面的「环形链表」中,一个表针指向最老的页面。

当发生缺页中断时,算法首先检查表针指向的页面:

  • 如果它的访问位位是 0 就淘汰该页面,并把新的页面插入这个位置,然后把表针前移一个位置;
  • 如果访问位是 1 就清除访问位,并把表针前移一个位置,重复这个过程直到找到了一个访问位为 0 的页面为止;

最不常用算法

当发生缺页中断时,选择访问次数最少的那个页面,并将其淘汰。

磁盘调度算法

先来先服务算法(FCFS)

根据进程请求访问磁盘的先后顺序进行调度。

优点:公平;如果请求访问的磁道比较集中的话,算法性能还算过的去

缺点:如果有大量进程竞争使用磁盘,请求访问的磁道很分散,则FCFS在性能上很差,寻道时间长。

最短寻找时间优先(SSTF)

SSTF算法会优先处理的磁道是与当前磁头最近的磁道。可以保证每次的寻道时间最短,但是并不能保证总的寻道时间最短。

优点:性能较好,平均寻道时间短

缺点:可能产生“饥饿”现象

产生饥饿的原因在于:磁头在一个小区域内来回来去地移动

扫描算法(SCAN)

只有磁头移动到最外侧磁道的时候才能往内移动,移动到最内侧磁道的时候才能往外移动。这就是扫描算法(SCN)的思想。由于磁头移动的方式很像电梯,因此也叫电梯算法

优点:性能较好,平均寻道时间较短,不会产生饥饿现象

缺点:只有到达最边上的磁道时才能改变磁头移动方向;SCAN算法对于各个位置磁道的响应频率不平均

LOOK调度算法

相当于扫描算法的改进版本

LOOK 调度算法就是为了解决这个问题,如果在磁头移动方向上已经没有别的请求,就可以立即改变磁头移动方向。(边移动边观察, 因此叫LOOK)

优点:比起SCAN算法来,不需要每次都移动到最外侧或最内侧才改变磁头方向,使寻道时间进一步缩短

循环扫描算法(C-SCAN)

SCAN算法对于各个位置磁道的响应频率不平均,而C-SCAN算法就是为了解决这个问题。

规定只有磁头朝某个特定方向移动时才处理磁道访问请求,而返回时直接快速移动至起始端而不处理任何请求。 (单方向处理请求)

优点:比起SCAN来,对于各个位置磁道的响应频率很平均。

缺点:只有到达最边上的磁道时才能改变磁头移动方向,另外,比起SCAN算法来,平均寻道时间更长。

CLOOK调度算法

C-SCAN算法的主要缺点是只有到达最边上的磁道时才能改变磁头移动方向,并且磁头返回时不一定需要返回到最边缘的磁道上。C-LOOK 算法就是为了解决这个问题。

如果磁头移动的方向上已经没有磁道访问请求了,就可以立即让磁头返回,并且磁头只需要返回到有磁道访问请求的位置即可。

优点:比起C-SCAN算法来,不需要每次都移动到最外侧或最内侧才改变磁头方向,使寻道时间进一步缩短

内存分配算法

连续分配

要求必须是一个连续的空间

单一连续分配

内存中只能有一道用户程序,用户程序独占整个用户区空间

优点:实现简单;无外部碎片;可以采用覆盖技术扩充内存;不一定需要采取内存保护(eg:早期的PC操作系统MS-DOS)

缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低。

固定分区分配

将整个用户空间划分为若千个固定大小的分区,在每个分区中只装入一道作业

分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合

分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分

动态分区分配

这种分配方式不会预先划分内存分区,而是在进程装入内存时根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。

首次适应算法

每次都从低地址开始查找,找到第一个能满足大小的空闲分区。

空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

最佳适应算法

优先使用更少的空闲区

如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链( 或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点:每次都选最小的分区进行分配,会留下越来越多的、很小的、难以利用的内存块。因此这种方法会产生很多的外部碎片。

最坏适应算法(最大适应算法)

为了解决最佳适应算法的问题即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。

如何实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点:每次都选最大的分区进行分配,虽然可以让分配后留下的空闲区更大,更可用,但是这种方式会导致较大的连续空闲区被迅速用完。如果之,后有“大进程”到达,就没有内存分区可用了。

临近适应算法

算法思想:首次适应算法每次都从链头开始查找的。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。

如何实现:空闲分区以地址递增的顺序排列( 可排成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点:邻近适应算法的规则市能会导致无论低地址、高地址部分的空闲分区都有相同的概率被使用,也就导致了高地址部分的大分区更可能被使用,划分为小分区,最后导致无大分区可用