操作系统 3.6-内存换出

换出算法总览

页面置换算法

  1. FIFO(先进先出)

    • 最简单的页面置换算法,淘汰最早进入内存的页面。

    • 优点:实现简单。

    • 缺点:可能会导致Belady异常,即增加内存反而降低性能。如果刚换入的页面马上又要换出,FIFO的性能会很差。

MIN(最小使用时间)

  • 理论上的最优算法,淘汰预计在未来最长时间不会被使用的页面。

  • 优点:理论上最优,可以保证最低的缺页率。

  • 缺点:实现复杂,因为需要预测页面未来的使用情况。

LRU(最近最少使用)

  • 淘汰最长时间未被访问的页面。

  • 优点:性能接近最优,实现相对简单。

  • 缺点:需要跟踪每个页面的使用历史,增加了系统开销。

FIFO

在操作系统中,FIFO(先进先出)页面置换算法是一种常见的页面置换策略

FIFO工作流程

FIFO(先进先出)页面置换算法是一种简单的页面置换策略,它基于这样一个原则:**最早进入内存的页面将是最早被替换出去的页面。**这种算法易于实现,但可能不是最高效的页面置换策略。下面是FIFO页面置换算法的工作流程:

  1. 页面命中

    • 如果页面已经在内存中,那么这是一个页面命中(page hit),不需要进行页面置换。
  2. 页面缺失

    • 如果页面不在内存中,那么这是一个页面缺失(page fault),需要进行页面置换。

    • 检查是否还有空的页框可用。如果有,将新页面加载到空的页框中。

    • 如果没有空的页框,根据FIFO算法,选择队列中最早进入内存的页面进行替换。

  3. 页面置换

    • 将选中的页面从内存中移除,并将新页面加载到该页框中。

    • 更新队列,将新页面添加到队列的末尾,并移除被替换的页面。

  4. 更新引用序列

    • 继续处理程序的页面引用序列,重复步骤2-5,直到所有页面引用都被处理。
  5. 评估性能

    • 计算缺页次数(page faults),这是评估页面置换算法性能的主要指标之一。

案例分析

根据您提供的幻灯片内容,我们可以看到一个具体的例子,其中分配了3个页框,页面引用序列为 ABCABDADBCBCB

在这个例子中,FIFO算法导致了7次缺页。在这个例子中,如果我们按照FIFO算法来操作,我们会看到以下置换过程:

  1. 开始时,内存为空,引用序列为 A B C A B D A D B C B

  2. 当引用 A 时,将其放入第一个页框,没有发生缺页。

  3. 引用 B 时,将其放入第二个页框,没有发生缺页。

  4. 引用 C 时,将其放入第三个页框,没有发生缺页。

  5. 再次引用 A 时,因为 A 已经在内存中,没有发生缺页。

  6. 引用 B 时,因为 B 已经在内存中,没有发生缺页。

  7. 引用 D 时,需要替换掉最早进入的 A,发生缺页。

  8. 引用 A 时,需要替换掉最早进入的 B,发生缺页。

  9. 引用 D 时,因为 D 已经在内存中,没有发生缺页。

  10. 引用 B 时,需要替换掉最早进入的 C,发生缺页。

  11. 引用 C 时,需要替换掉最早进入的 A,发生缺页。

  12. 引用 B 时,因为 B 已经在内存中,没有发生缺页。

在这个过程中,总共发生了7次缺页。

MIN

MIN页面置换算法,也被称为OPT(Optimal,最优)算法,是一种理论上最优 的页面置换算法。它选择将来最长时间内不会被使用的页面进行置换。由于MIN算法需要知道未来的页面引用信息,这在实际中是不可能的,因此它通常用于理论分析和比较其他算法的性能。

MIN算法工作流程

  1. 初始化

    • 假设系统有固定数量的页框(page frames),用于存储内存中的页面。
  2. 页面引用

    • 当程序引用一个页面时,系统检查该页面是否已经在内存中(即是否在页框中)。
  3. 页面命中

    • 如果页面已经在内存中,那么这是一个页面命中(page hit),不需要进行页面置换。
  4. 页面缺失

    • 如果页面不在内存中,那么这是一个页面缺失(page fault),需要进行页面置换。

    • 检查所有在内存中的页面,确定哪个页面在未来最长时间内不会被引用。

  5. 页面置换

    • 将选中的页面从内存中移除,并将新页面加载到该页框中。
  6. 更新引用序列

    • 继续处理程序的页面引用序列,重复步骤2-5,直到所有页面引用都被处理。
  7. 评估性能

    • 计算缺页次数(page faults),这是评估页面置换算法性能的主要指标之一。

图中案例分析

在图中的案例中,我们有3个页框,页面引用序列为 ABCABDADBCBCB。根据MIN算法,我们可以看到以下置换过程:

  1. 开始时,内存为空,引用序列为 A B C A B D A D B C B

  2. 引用 A 时,将其放入第一个页框,没有发生缺页。

  3. 引用 B 时,将其放入第二个页框,没有发生缺页。

  4. 引用 C 时,将其放入第三个页框,没有发生缺页。

  5. 再次引用 A 时,因为 A 已经在内存中,没有发生缺页。

  6. 引用 B 时,因为 B 已经在内存中,没有发生缺页。

  7. 引用 D 时,需要替换掉将来最长时间内不会被使用的页面。在这个例子中,C 在未来的引用序列中出现的最晚,因此被替换,发生缺页。

  8. 引用 A 时,因为 A 已经在内存中,没有发生缺页。

  9. 引用 D 时,因为 D 已经在内存中,没有发生缺页。

  10. 引用 B 时,因为 B 已经在内存中,没有发生缺页。

  11. 引用 C 时,需要替换掉将来最长时间内不会被使用的页面。在这个例子中,A 在未来的引用序列中出现的最晚,因此被替换,发生缺页。

  12. 引用 B 时,因为 B 已经在内存中,没有发生缺页。

在这个过程中,总共发生了5次缺页。

LRU

LRU(最近最少使用)页面置换算法是一种非常流行且有效的页面置换策略。它基于这样一个假设:如果一个页面最近被访问过,那么它在未来很可能也会被访问;相反,如果一个页面很长时间没有被访问,那么它在未来被访问的可能性就较小。 因此,LRU算法会选择最长时间未被访问的页面进行置换。就是用历史推测未来

LRU算法工作流程

  1. 初始化

    • 假设系统有固定数量的页框(page frames),用于存储内存中的页面。

    • 初始化一个数据结构(如链表或栈),用于跟踪每个页面最后一次被访问的时间。

  2. 页面引用

    • 当程序引用一个页面时,系统检查该页面是否已经在内存中(即是否在页框中)。
  3. 页面命中

    • 如果页面已经在内存中,那么这是一个页面命中(page hit)。更新该页面的最后访问时间。
  4. 页面缺失

    • 如果页面不在内存中,那么这是一个页面缺失(page fault),需要进行页面置换。

    • 检查所有在内存中的页面,确定哪个页面最长时间未被访问。

  5. 页面置换

    • 将选中的页面从内存中移除,并将新页面加载到该页框中。

    • 更新新页面的最后访问时间。

  6. 更新引用序列

    • 继续处理程序的页面引用序列,重复步骤2-5,直到所有页面引用都被处理。
  7. 评估性能

    • 计算缺页次数(page faults),这是评估页面置换算法性能的主要指标之一。

图中案例分析

在图中的案例中,我们有3个页框,页面引用序列为 ABCABDADBCBCB。根据LRU算法,我们可以看到以下置换过程:

  1. 开始时,内存为空,引用序列为 A B C A B D A D B C B

  2. 引用 A 时,将其放入第一个页框,没有发生缺页。

  3. 引用 B 时,将其放入第二个页框,没有发生缺页。

  4. 引用 C 时,将其放入第三个页框,没有发生缺页。

  5. 再次引用 A 时,因为 A 已经在内存中,更新其最后访问时间,没有发生缺页。

  6. 引用 B 时,因为 B 已经在内存中,更新其最后访问时间,没有发生缺页。

  7. 引用 D 时,需要替换掉最长时间未被访问的页面。在这个例子中,C 是最长时间未被访问的页面,因此被替换,发生缺页。

  8. 引用 A 时,因为 A 已经在内存中,更新其最后访问时间,没有发生缺页。

  9. 引用 D 时,因为 D 已经在内存中,更新其最后访问时间,没有发生缺页。

  10. 引用 B 时,因为 B 已经在内存中,更新其最后访问时间,没有发生缺页。

  11. 引用 C 时,需要替换掉最长时间未被访问的页面。在这个例子中,A 是最长时间未被访问的页面,因此被替换,发生缺页。

  12. 引用 B 时,因为 B 已经在内存中,更新其最后访问时间,没有发生缺页。

在这个过程中,总共发生了5次缺页。

时间戳实现

图中展示了如何使用时间戳来准确实现LRU(最近最少使用)页面置换算法。**这种方法通过为每个页面维护一个时间戳来记录页面最后一次被访问的时间。**当需要进行页面置换时,选择具有最小时间戳的页面进行淘汰,即该页面是最近最少使用的。

实现步骤

  1. 初始化

    • 为每个页面分配一个时间戳变量,初始值设为0。

    • 设置一个全局时钟,用于生成时间戳。

  2. 页面引用

    • 当程序引用一个页面时,系统检查该页面是否已经在内存中。
  3. 页面命中

    • 如果页面已经在内存中,更新该页面的时间戳为当前的全局时钟值。
  4. 页面缺失

    • 如果页面不在内存中,需要进行页面置换。

    • 遍历所有在内存中的页面,找到具有最小时间戳的页面,即最长时间未被访问的页面。

  5. 页面置换

    • 将选中的页面从内存中移除,并将新页面加载到该页框中。

    • 更新新页面的时间戳为当前的全局时钟值。

  6. 更新全局时钟

    • 每次页面访问后,无论是否发生页面置换,都递增全局时钟值。
  7. 评估性能

    • 计算缺页次数,评估页面置换算法的性能。

图中案例分析

在图中的案例中,我们有3个页框,页面引用序列为 ABCABDADBCBCB。以下是使用时间戳实现LRU算法的具体步骤:

  1. 开始时,内存为空,时间戳表也为空。

  2. 引用 A 时,将 A 放入第一个页框,时间戳设为1。

  3. 引用 B 时,将 B 放入第二个页框,时间戳设为2。

  4. 引用 C 时,将 C 放入第三个页框,时间戳设为3。

  5. 再次引用 A 时,更新 A 的时间戳为4(页面命中)。

  6. 引用 B 时,更新 B 的时间戳为5(页面命中)。

  7. 引用 D 时,需要进行页面置换。此时,C 的时间戳最小(3),因此选择 C 进行淘汰,将 D 放入第三个页框,时间戳设为6。

  8. 引用 A 时,更新 A 的时间戳为7(页面命中)。

  9. 引用 D 时,更新 D 的时间戳为8(页面命中)。

  10. 引用 B 时,更新 B 的时间戳为9(页面命中)。

  11. 引用 C 时,需要进行页面置换。此时,A 的时间戳最小(4),因此选择 A 进行淘汰,将 C 放入第一个页框,时间戳设为10。

  12. 引用 B 时,更新 B 的时间戳为11(页面命中)。

在这个过程中,总共发生了5次缺页。

难实现!!!

页码栈实现

图中展示了如何使用页码栈来实现LRU(最近最少使用)页面置换算法。**这种方法通过维护一个栈(或队列)来跟踪页面的使用顺序。**当需要进行页面置换时,选择栈底的页面进行淘汰,即该页面是最近最少使用的。

实现步骤

  1. 初始化

    • 创建一个栈,用于存储当前在内存中的页面。

    • 初始化一个映射(如哈希表),用于快速查找页面在栈中的位置。

  2. 页面引用

    • 当程序引用一个页面时,系统检查该页面是否已经在内存中。
  3. 页面命中

    • 如果页面已经在内存中,将该页面移到栈顶(表示最近被访问过)。
  4. 页面缺失

    • 如果页面不在内存中,需要进行页面置换。

    • 选择栈底的页面进行淘汰(最长时间未被访问的页面)。

  5. 页面置换

    • 将选中的页面从栈中移除,并将新页面加载到栈顶。
  6. 更新映射

    • 更新映射,以反映新页面在栈中的位置。
  7. 评估性能

    • 计算缺页次数,评估页面置换算法的性能。

图中案例分析

在图中的案例中,我们有3个页框,页面引用序列为 ABCABDADBCBCB。以下是使用页码栈实现LRU算法的具体步骤:

  1. 开始时,栈为空。

  2. 引用 A 时,将 A 压入栈顶。

  3. 引用 B 时,将 B 压入栈顶。

  4. 引用 C 时,将 C 压入栈顶。

  5. 再次引用 A 时,将 A 从栈中移出并重新压入栈顶(页面命中)。

  6. 引用 B 时,将 B 从栈中移出并重新压入栈顶(页面命中)。

  7. 引用 D 时,需要进行页面置换。此时,栈底是 C,因此选择 C 进行淘汰,将 D 压入栈顶。

  8. 引用 A 时,将 A 从栈中移出并重新压入栈顶(页面命中)。

  9. 引用 D 时,将 D 从栈中移出并重新压入栈顶(页面命中)。

  10. 引用 B 时,将 B 从栈中移出并重新压入栈顶(页面命中)。

  11. 引用 C 时,需要进行页面置换。此时,栈底是 A,因此选择 A 进行淘汰,将 C 压入栈顶。

  12. 引用 B 时,将 B 从栈中移出并重新压入栈顶(页面命中)。

在这个过程中,总共发生了5次缺页。

难实现!!!

SCR

图中展示的是Clock算法,也称为Second Chance算法,这是一种近似实现LRU(最近最少使用)页面置换策略的方法。它通过给**每个页面添加一个引用位(reference bit)来模拟时间戳,从而实现页面的置换决策。**这种方法比维护全局时间戳或页码栈的实现方式要简单,且实现代价较小。

Clock算法实现步骤

  1. 初始化

    • 为每个页框分配一个引用位(通常为一个二进制位),初始值设为0。

    • 创建一个指针(或称为"时钟指针"),用于扫描页框。

  2. 页面引用

    • 当程序引用一个页面时,系统检查该页面是否已经在内存中。

    • 如果页面命中,硬件自动将该页面的引用位设置为1。

  3. 页面缺失

    • 如果页面不在内存中(页面缺失),时钟指针开始扫描页框。

    • 扫描过程中,如果遇到引用位为1的页面,将其引用位清0,并继续扫描下一个页面。

    • 如果遇到引用位为0的页面,选择该页面进行淘汰,并加载新页面到该页框中。

  4. 更新引用位

    • 当新页面加载到页框后,将其引用位设置为1。
  5. 循环扫描

    • 如果在一轮扫描中没有找到引用位为0的页面(即所有页面的引用位都被设置为1),则选择第一个引用位为1的页面进行淘汰,并重新设置其引用位为0。

    • 如果遇到引用位为0的页面,淘汰。

  6. 评估性能

    • 计算缺页次数,评估页面置换算法的性能。

图中案例分析

图中展示了Clock算法的工作流程,其中每个页框都有一个引用位(R=0或R=1)。以下是具体步骤:

  1. 开始时,所有引用位都设置为0。

  2. 当访问页面时,硬件自动将对应的引用位设置为1。

  3. 当需要置换页面时,时钟指针开始扫描页框。

  4. 在扫描过程中,如果遇到引用位为1的页面,将其引用位清0,并继续扫描

  5. **如果遇到引用位为0的页面,选择该页面进行淘汰,**并加载新页面到该页框中,同时将新页面的引用位设置为1。

  6. 如果在一轮扫描中没有找到引用位为0的页面(即所有页面的引用位都被设置为1),则选择第一个引用位为1的页面进行淘汰,并重新设置其引用位为0

Clock算法改造优化

问题描述

  1. 缺页很少时的情况

    • 如果系统中的缺页很少,**可能会导致所有页面的引用位(R位)都被设置为1。**这种情况下,Clock算法可能会退化为FIFO算法,因为它会不断地扫描直到找到一个可以替换的页面。
  2. 记录太长的历史信息

    • 如果系统中的页面长时间没有被替换,**它们的引用位可能会一直保持为1,**这会导致算法效率降低,因为它需要扫描更多的页面来找到一个R位为0的页面。

改造建议:

  1. 定时清除R位

    • 为了解决R位长时间为1的问题,可以定时清除所有页面的R位。这样可以确保算法不会记住太长的历史信息,从而避免退化为FIFO算法。
  2. 使用两个扫描指针

    • 引入一个快速移动的扫描指针用于清除R位,一个慢速移动的扫描指针用于选择淘汰页面。这样可以提高清除R位的效率,同时保持选择淘汰页面的准确性。

实现步骤:

  1. 初始化

    • 为每个页框分配一个引用位(R位),初始值设为0。

    • 创建两个扫描指针,一个用于清除R位(快速移动),一个用于选择淘汰页面(慢速移动)。

  2. 页面引用

    • 当程序引用一个页面时,将该页面的R位设置为1。
  3. 页面缺失

    • 如果页面不在内存中,慢速扫描指针开始扫描页框以选择淘汰页面。

    • 如果遇到R位为1的页面,将其R位清0,并继续扫描。

    • 如果遇到R位为0的页面,选择该页面进行淘汰,并加载新页面到该页框中,同时将新页面的R位设置为1。

  4. 清除R位

    • 快速扫描指针周期性地扫描所有页框,将所有页面的R位清0。
  5. 更新扫描指针

    • 每次页面置换后,慢速扫描指针前移一位。

    • 快速扫描指针在清除完所有R位后也前移一位。

  6. 评估性能

    • 计算缺页次数,评估页面置换算法的性能。

给进程分配多少页框

分配页框的挑战:

  1. 分配过多

    • 如果给每个进程分配过多的页框,虽然可以减少缺页率,提高内存的高效利用,但这样做会减少系统中可用的页框总数,导致无法同时运行更多的进程。
  2. 分配过少

    • 如果分配的页框太少,每个进程的缺页率会增大,导致更多的页面置换操作,从而增加进程等待调页完成的时间,降低CPU利用率。

颠簸(Thrashing)现象:

  • 定义:颠簸是指系统因为进程的缺页率过高,导致大部分时间都在进行页面置换操作,而实际的CPU利用率却很低的现象。

  • 原因:当系统中进程数量过多时,每个进程分配到的页框数量减少,导致缺页率增加。随着缺页率的增加,进程需要花费更多的时间等待页面置换完成,从而减少了CPU的有效工作时间。

  • 影响:颠簸会导致系统性能急剧下降,因为CPU大部分时间都在处理页面置换,而不是执行用户进程。

图中现象分析:

图中展示了CPU利用率与多道程序程度(即系统中同时运行的进程数量)之间的关系。随着进程数量的增加,CPU利用率先增加后减少,形成一个峰值。这个峰值之后,CPU利用率急剧下降,这就是颠簸现象。

解决策略:

  1. 合理分配页框

    • 需要找到一个平衡点,即合理分配页框数量,使得系统中的进程既能有效利用内存,又不至于因为缺页率过高而导致颠簸。

通过这些策略,可以有效地避免颠簸现象,提高系统的稳定性和性能。

相关推荐
weifexie20 分钟前
ruby可变参数
开发语言·前端·ruby
千野竹之卫21 分钟前
3D珠宝渲染用什么软件比较好?渲染100邀请码1a12
开发语言·前端·javascript·3d·3dsmax
sunbyte21 分钟前
初识 Three.js:开启你的 Web 3D 世界 ✨
前端·javascript·3d
半兽先生42 分钟前
WebRtc 视频流卡顿黑屏解决方案
java·前端·webrtc
南星沐2 小时前
Spring Boot 常用依赖介绍
java·前端·spring boot
孙_华鹏2 小时前
手撸一个可以语音操作高德地图的AI智能体
前端·javascript·coze
zhangxingchao2 小时前
Jetpack Compose 动画
前端
@PHARAOH3 小时前
HOW - 缓存 React 自定义 hook 的所有返回值(包括函数)
前端·react.js·缓存
拉不动的猪3 小时前
设计模式之--------工厂模式
前端·javascript·架构
前端开发张小七3 小时前
16.Python递归详解:从原理到实战的完整指南
前端·python