【操作系统】第六章:页面置换算法(Part1:局部页面置换算法)

简介: 【操作系统】第六章:页面置换算法(Part1:局部页面置换算法)

目录


  • 局部页面置换算法
  • 最优页面置换算法
  • FIFO先进先出
  • LRU最近最久未使用算法
  • Clock时钟页面置换算法
  • 二次机会法Enhanced Clock
  • Belady现象
  • FIFO/LRU/Clcok的比较


正文


局部页面置换算法


功能:当缺页中断发生,需要调入新的页但是物理内存已满,此时需要把当前一部分页换出去,空出空间。选择内存中哪一个页被替换

目标:

1.尽可能减少换入和换出的次数。具体来说,把未来不再使用或者近期不会使用/较少使用的页面换出,通常只能在局部性原理指导下依据过去的统计数据预测。

2.页面锁定。 有一些物理页是需要常驻内存的,比如OS相关的代码和数据,这些随时都有可能访问,那么这些页我们需要常驻访问。我们用页面锁定技术,把相关的页放在内存里,使得这些页不在页面置换算法的考虑范围内。

例子:

a8bf9d30bf7b8a08436f3ae926707b5c_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

(3,0)这个序列的意思是访问了第三个页面的第0个便宜。也就说(页序号,偏移量object)。我们这里可以忽略他的偏移量,只考虑页序号。因为只有当一个页不存在的时候,才会产生缺页中断,才需要考虑页面置换。在同一个页里面有多次访问,只有第一次访问才有可能产生缺页中断,所以我们可以忽略偏移量只考虑页号。


最优页面置换算法


e4620b57807b04b715c7e2995de2a0a9_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

这个算法可以说是一个不太实际的算法,但是我们可以把它作为一个评价标准。这个算法根据未来的情况进行推算,一般来说缺页次数产生最少。一般我们用其他页面置换算法运行后的结果与最优页面置换算法比较,比较缺页次数,只要能够尽量逼近最优选法,我们就可以认为这是一种比较好的算法。

0524dd71b8d51eec42e09e814bb521ef_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

根据最优页面置换算法,由于访问之前物理内存中已经存储了abcd,所以前四次访问不会改变物理内存中的页。但是当第五次访问发生时,根据换出距离下次访问时间最长的页,得应该换出d置入e,则此时物理内存中是abce,没有d。则当下次访问d时,应该换出最长等待时间的c。第十次访问后,物理内存的页编号是abde

117bf08126ba4b52046e19d8a72e1a55_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png


FIFO先进先出


e4e477bf0e95516edfac084f878e24e1_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

链表(List),典例是程序中的Queue。

产生缺页中断次数比较多。

Belady现象:当我们给一个程序分配更多的物理页时,它的缺页次数应该减少,但是FIFO可能会导致分配的物理页越多,缺页次数增加的现象。

ea98b83bfafde52cd2af5e6616e617a9_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

先入先出原则,替换list中滞留时间最久的那一个。

内容 内容 内容 内容 时间点
a b c d 0
a b c d 1
a b c d 2
a b c d


a b c d


e b c d


e b c d


e a c d


e a b d


e a b c


d a b c



LRU最近最久未使用算法


7b979c710ed13241c18fb8adb0d99a6a_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

和最长滞留时间不同,最长滞留时间是在物理内存中驻留时间很久,但是他可能在近期被访问过;这个算法是换出在队列中最长时间没有被访问的页。根据程序局部性原理,在最近的一小段时间内,程序访问的代码和数据未来还有可能会继续访问,所以LRU就是合理的,因为反推局部性原理,一段时间内没用,那么接下来一段时间也可能不会用到。

c4380d64ab984f352a18b7b4074c02ea_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

缺页中断:3次

*:较久访问 标记越多,程序内优先级越高

粗体:置换/更新访问,当内存内数据被访问时,其替换优先级清零


访问请求 c a d b e b a b c d 最终
默认a a a a* a** a*** a**** a a* a** a*** a
默认b b b b b b* b b* b b* b** b
默认c c c* c** c*** e e* e** e*** e**** d d
默认d d d d d* d** d*** d**** d***** c c c

LRU需要记录各个页面使用时间的先后顺序,开销比较大。目前有两种可能的实现方法。

1aed28f11ea41c7728a9ae7d69753a7a_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

1.使用链表[List]。每当一个页面被访问时,如果内存中有这个页,则将其放在首,最久访问自然会在不断换头的过程中排序放在尾部。没有的数据则淘汰链表尾部,然后插入首部。

例子:

内容 内容 更新
a b c d default
c a b d c
e c a b e
a e c b a

2.使用堆栈。

f0ddebb870c8316f047b2f2edecaacb5_2020042015510288.png

页面置入栈顶后,查找是否有相同页号这个过程开销比较大。栈底一定是最久未被使用,所以需要替换时,直接替换栈底。

0a81ebaa33725d354841d8ca23b8ac62_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

总结:LRU算法,结果虽然不错,但是他的开销比较大。他不是一个合适的实现方法,OS设计讲究高效且简洁,为了实现效果而花费很大代价,则得不偿失。需要一个平衡。


Clock时钟页面置换算法


LRU的近似,FIFO的改进。没有LRU的精确,但是能够近似的表明访问的先后顺序状态的算法,开销自然小很多。

页表项中的acess位,访问后0变成1,这个过程由硬件完成,不需要软件参与。但是我们的软件可以对其进行清零操作和置1操作。所以,当CPU访问到这个页的时候,会把acess bit置1。因此我们可以粗略估计,如果这个页的acess bit 是1,我们就认为他被访问了,是0则认为他没有被访问。只用了一个比特表示时间信息,虽然不精确但是有效。然后我们把程序访问的所有页面组成一个环形列表,并通过一个指针指向当前页,并且探测他是否是近似最老的页。老的判断就是:因为OS会定期把访问位清零,你一旦访问页后CPU又会置1,然后看这个访问位01状态,0是老页,就可以把这个页换出去。

2d9b066bcb84fbba53c9f4ff596940db_20200420170750837.gif


抽象成时钟后,如图所示,指针指向某一物理内存时,检测其访问为是否为1,为1则将其置0且指针走向下一项。为0则其页帧就需替换出去。如果内存中有这一项且其访问位为0,则不需要指针转动检测,只需要将这一项置1即可。且这一操作不会导致指针转动到下一个位置【指针位置不变】。

bb9dae7ea8a3bd12050975c43453e122_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

解析:

阶段 变化
1~4 物理内存中有这一项,所以访问位0=>1,指针不转动,默认停在首位
5 由于物理内存中所有项访问位均为1,指针空转一圈。此时所有访问位置0,指针处于首位,指向a。此时更新页帧(a->e)且将访问位置1
6 b已存在于内存,更新访问位为1。指针不变,仍指b
7 指针指向b,将b置0后指向下一位。由于c访问位为0,则将c替换为a并置1,指针向下一位移动。
8 更新b,指针不变,指向d
9 更新d为c并置1.此时内存中所有访问位均为1
10 进行空转一周,访问位全部清0,此时指针将从头开始旋转,指向首部,替换第一个页帧号。e=>d并置1

也就说当内存中访问位全为1时,该算法退化为FIFO


二次机会法Enhanced Clock


Clock算法是对访问进行标示,访问其实就是读写。这一过程并不能区分读和写,只能区分大致是否访问。因此对脏页的处理代价就比较大。写操作进行后,硬件会将脏位置1

脏位(dirty bit):如果页是写操作,置1;读操作,置0

在访问过程中,如果全是读操作,就意味着内存中与硬盘中的内容是一致的。所以如果替换这一页的时候,我们不需要写回硬盘,只需要释放内存空间(开销小);但是如果这一页在内存访问过程中,是对这一页进行写操作,也就说内存与硬盘中内容可能不一致,我们替换这一页时,需要把这一页的内容写会硬盘,来确保数据一致。

所以用上脏位,配合Clock算法可以来减少对硬盘的访问(写回操作的次数)

算法解析:

8e74914c30bdd31505a388eabbd058ea_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

根据图示:

只有脏位(图中修改位)和访问位(图中使用位)均为0时,才会置换指针指向的页,然后将其访问位置1。当脏位和访问位仅有一个1时,将这一个1置0,指针指向下一位。均为1时,访问位置0,脏位不变,指针下移。

也就说如果某一个页他的两个校验位均为1,指针经过他两次才会将其全部清零,也就说第三次才会被置换。

7d647731228c791ce7eeb531dc3f121e_20200420171021699.gif


通过这种算法,可以吧脏位(经常使用的页)有更多的机会留在内存中,而不会被频繁换入换出,而只读页会更优先的换出,使得被写过的页换出的概率减少,对硬盘的访问次数也就随之减少。这种算法修改了脏位,也就说每次替换都要写回主存。

理解hit】相比较访问位相同的页,脏位为1的页将赋予它多一次机会,优先将读操作的页换出去。

图示:aw中,w代表是这次访问是写操作。

image.gif


阶段 变化
1~4 物理内存中有这一项,所以访问位0=>1,指针不转动,默认停在首位
5 指针空转一轮,然后从上到下分别变为01 01 00 00,指针回到首部,开始扫,数据变为00 00 c替换e 10 00 abed
6 b已存在于内存,更新访问位为1。00 10 10 00 指针不变
7 a的写操作。11 10 10 00 abed
8 与7相同
9 更新d为c并置1。 11 10 10 10 abec
10 进行空转一周,访问位全部清0,此时指针将从头开始旋转,指向首部,替换第一个页帧号。d=>a并置1 01 10 00 00 adec



Belady现象


当我们给正在运行的程序分配的物理页越多,它产生缺页的次数应该越少。但是当采取了某些页面置换算法后,物理内存分配的越多缺页现象反而增加的现象。典例是FIFO。因为FIFO替换的页面不是当前程序近期不会访问或者不常用的页面,它置换出去的页很可能接下来要使用。

d00342822cf05647a76a143d4e74e124_20200421092024672.gif

如上图所示,FIFO的页面置换情况下出现的缺页现象。

阶段 变化
1~7 满足FIFO条件,先进先出,发生缺页后头部替换出去且剩余内容顺位移动,在尾部加入当前要访问的页帧号

8~9

第七次访问后,此时链表中的数据是1-2-5,此时再次访问1和2这个已经存在于链表中的页帧,这里不会产生缺页中断但是整个链表没有体现出时间相关的信息,此时1和2虽然是链表中放的比较久的页,但是这里并不能体现他们的驻留时间。它只体现了它存在的先后时间却没有体现动态访问中访问时间先后。
10~12 未命中,缺页中断,FIFO先入先出替换


上面是给链表设置了三个页的空间,那么如果我们设置多一个空间又会怎样呢?理论上应该是缺页次数更少才对。

17f67ac61dc595e2ae203a581b7d51a1_202004210930186.gif

如图,缺页次数反而比之前更多了。这就是Belady现象。

反观LRU算法

71441c82b89b86037bd0a273adec07de_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0NoYWhvdA==,size_16,color_FFFFFF,t_70.png

同样的访问序列,当在内存分三个页帧时,产生了10次缺页,当内存中页帧分配量增加1时,只产了8次缺页。也就说随着物理页帧空间的增加,缺页次数减少了,LRU没有Belady现象。

LRU算法符合栈算法的特点,栈算法的特点之一就是给的物理页帧越多,它的缺页次数越少。


FIFO/LRU/Clcok的比较


LRU和FIFO都是先进先出的思路,所以可以用链表或者栈来表示它的访问次序和驻留时间,但是LRU算法除了滞留时间还考虑了最近访问时间,所以当访问到内存中已存在的页帧时,他会将其置于head其他页顺序推移。这就是FIFO和LRU的最大区别。程序局部性特点越好,LRU算法就会产生越少的缺页次数。但是如果程序没有很好的局部性特点,则LRU会退化为FIFO算法,甚至完全等价。

Clock算法是LRU算法的一种近似,用1-2位bit来模拟访问时间,所以他有效逼近LRU算法且开销小。

LRU算法开销过大,FIFO性能不佳,所以折中我们会偏爱Clock算法。每一次访问时,不必动态的去调整该页面在链表中的顺序,而仅需要做一个标记,然后等待缺页中断发生时,再把它移动到链表尾部。对于内存中未被访问的页面,Clock与LRU一样好。而对于访问过的页面,则比LRU算法差。


目录
相关文章
|
1月前
|
算法 调度 UED
探索操作系统的心脏:调度算法的奥秘与影响
【10月更文挑战第9天】 本文深入探讨了操作系统中至关重要的组件——调度算法,它如同人体的心脏,维持着系统资源的有序流动和任务的高效执行。我们将揭开调度算法的神秘面纱,从基本概念到实际应用,全面剖析其在操作系统中的核心地位,以及如何通过优化调度算法来提升系统性能。
|
17天前
|
算法
时钟置换算法
【10月更文挑战第25天】时钟置换算法是一种简单而有效的页面置换算法,它通过使用位标志和环形链表的结构,在一定程度上平衡了算法的复杂性和性能表现。虽然它存在一些局限性,但通过改进和与其他算法的结合,可以在不同的系统环境中发挥重要作用,提高虚拟内存管理的效率和系统的整体性能。
44 8
|
17天前
|
机器学习/深度学习 算法 数据挖掘
提高时钟置换算法的性能
【10月更文挑战第25天】通过上述一种或多种方法的综合应用,可以在不同程度上提高时钟置换算法的性能,使其更好地适应各种复杂的系统环境和应用场景,提高虚拟内存管理的效率和系统的整体性能。
35 5
|
17天前
|
算法
虚拟内存的页面置换算法有哪些?
【10月更文挑战第25天】不同的页面置换算法各有优缺点,在实际应用中,操作系统会根据不同的应用场景和系统需求选择合适的页面置换算法,或者对算法进行适当的改进和优化,以平衡系统的性能、开销和资源利用率等因素。
37 5
|
22天前
|
算法 大数据 Linux
深入理解操作系统之进程调度算法
【10月更文挑战第24天】本文旨在通过浅显易懂的语言,带领读者深入了解操作系统中的进程调度算法。我们将从进程的基本概念出发,逐步解析进程调度的目的、重要性以及常见的几种调度算法。文章将通过比喻和实例,使复杂的技术内容变得生动有趣,帮助读者建立对操作系统进程调度机制的清晰认识。最后,我们还将探讨这些调度算法在现代操作系统中的应用和发展趋势。
|
1月前
|
算法 调度 UED
深入理解操作系统的进程调度算法
【10月更文挑战第7天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。它不仅影响系统的性能和用户体验,还直接关系到资源的合理分配。本文将通过浅显易懂的语言和生动的比喻,带你一探进程调度的秘密花园,从最简单的先来先服务到复杂的多级反馈队列,我们将一起见证算法如何在微观世界里编织宏观世界的和谐乐章。
|
1月前
|
边缘计算 算法 调度
探究操作系统的心脏:调度算法的进化与影响
【10月更文挑战第2天】 本文深入探讨了操作系统中核心组件——调度算法的历史演变、关键技术突破及其对现代计算的影响。通过详细回顾从单任务到多任务、实时系统及分布式计算环境下调度算法的发展,文章揭示了这些算法如何塑造我们的数字世界,并对未来的趋势进行了展望。不同于传统的摘要,本文特别聚焦于技术细节与实际应用的结合点,为读者提供一幅清晰的技术演进蓝图。
46 4
|
1月前
|
算法 调度 UED
探索操作系统的心脏:进程调度算法
【9月更文挑战第32天】在数字世界的每一次心跳中,都隐藏着一个不为人知的英雄——进程调度算法。它默默地在后台运作,确保我们的命令得到快速响应,应用程序平稳运行。本文将带你走进操作系统的核心,一探进程调度的奥秘,并通过代码示例揭示其背后的智慧。准备好跟随我一起深入这趟技术之旅了吗?让我们开始吧!
|
1月前
|
算法
有哪些页面置换算法?
页面置换算法(Page Replacement Algorithms)在计算机操作系统中用于管理虚拟内存。
|
1月前
|
存储 算法 C语言
MacOS环境-手写操作系统-17-内存管理算法实现
MacOS环境-手写操作系统-17-内存管理算法实现
37 0