Python 程序实现最近最少使用页面置换算法

2024年8月29日 | 阅读 7 分钟

页面替换算法在操作系统中用于采用分页技术来管理内存,以确定在添加新页面时应删除哪个页面。每次引用新页面但它不在内存中时,就会发生页面错误,并且操作系统会将引用的页面替换为最近引用的页面。各种页面替换算法提供了不同的建议来选择合适的替换页面。每种算法都力求减少页面错误的数量。

最近最少使用 (LRU) 算法是一种贪心算法。在此算法中,要替换的页面是最近最少使用的。该思想基于引用局部性。最近最少使用的页面被认为不太重要。

让我们举个例子。我们有一个字符串,它决定了页面引用序列 3 0 1 2 1 3 5 1 2 5 0 1 2。页面槽的容量为 3。

  • 起初,所有页面槽都是空的,因此页面 3 0 1 被放入空槽中 -> 3 次页面错误
  • 2 不在内存中,最近最少使用的页面将被替换,即 3 -> 1 次页面错误。
  • 当 1 进来时,它已经存在于内存中,因此不会替换任何页面,但 1 现在是最常使用的页面,因此页面引用的顺序变为 0 3 1 而不是 0 1 3 -> 0 次页面错误
  • 3 已经存在于内存中,因此不会发生页面错误。页面引用顺序为 0 1 3 -> 0 次页面错误。
  • 5 不在内存中,因此它将替换 0,因为 0 是最近最少使用的页面 -> 1 次页面错误
  • 我们可以继续这个过程,并计算给定页面引用序列的总页面错误次数。

方法一

设 C 为内存可容纳的总页数。设 S 为包含当前在内存中的页面的集合。

  1. 我们将从遍历给定的页面引用序列开始。
    • 我们将检查内存中的页面数量是否少于其容量。
      • 我们将当前页面插入到集合 S 中。这将一直持续到内存容量集被填满为止。
      • 除了这些步骤之外,我们还将维护最近使用的页面的记录。我们将通过创建每个页面的索引映射来实现此步骤。
      • 此外,我们还需要计算页面错误次数。因此,每次我们更新集合 S 时,我们都会增加页面错误次数。
    • 否则,
      如果集合 S 已达到容量,我们将检查当前页面是否已存在于集合中。如果为 True,我们将不做任何操作。
      如果为 False,
      • 我们将从集合中的页面中找到最近最少使用的页面。我们将使用索引映射找到它。找到页面后,我们将用当前页面替换该页面。
      • 因此,我们需要通过添加当前页面并删除 LRU 页面来更新集合 S。
      • 由于我们更新了集合 S,因此需要增加页面错误计数。
  2. 此外,我们还需要更新索引映射中当前页面的索引。
  3. 最后,我们将返回总页面错误次数。
  4. 下面是实现上述算法的 Python 程序。

代码

输出

s = {3}
s = {0, 3}
s = {0, 1, 3}
s = {0, 1, 2}
s = {0, 1, 2}
s = {3, 1, 2}
s = {1, 3, 5}
s = {1, 3, 5}
s = {1, 2, 5}
s = {1, 2, 5}
s = {0, 2, 5}
s = {0, 1, 5}
s = {0, 2, 1}
The total number of page faults is: 10

时间复杂度:集合和映射操作的平均时间复杂度为 O(1)。在最坏的情况下,复杂度将达到 O(n)。但是,由于 O(n) 是主导项,因此该程序的复杂度为 O(n)。

空间复杂度:空间复杂度等于内存可容纳页面的给定容量。

方法二:(不使用哈希表)

在此方法中,我们不使用集合。以下是算法方法。

  • 该程序通过使用双端队列数据结构来实现页面替换技术。
  • 该方法根据给定的容量在内存中保留一定数量的页面,并在引用新页面时替换它们。
  • 通过使用数组模拟页面查询,代码会跟踪执行过程中发生的页面错误数量。
  • 内存中当前存在的页面通过双端队列数据结构进行更新。
  • 代码在页面请求模拟过程中输出了发生的页面错误总数。

下面是使用 Python 实现此算法的代码。

代码

输出

s = [3]
s = [3, 0]
s = [3, 0, 1]
s = [0, 1, 2]
s = [0, 2, 1]
s = [2, 1, 3]
s = [1, 3, 5]
s = [3, 5, 1]
s = [5, 1, 2]
s = [1, 2, 5]
s = [2, 5, 0]
s = [5, 0, 1]
s = [0, 1, 2]
The total number of page faults is: 10

时间复杂度:此 LRU 算法的时间复杂度为 O(n)。此时间复杂度的原因是,我们使用了线性 for 循环来遍历给定的页面引用序列。页面错误以恒定时间执行。

空间复杂度:此 LRU 算法的空间复杂度为 O(n)。这里 n 是给定页面引用序列的长度。

在此程序中,我们还可以确定模拟过程中发生的总页面命中次数。我们需要创建另一个变量来存储页面命中的计数。

当前页面已在内存中的次数称为页面命中。