第二次机会(或时钟)页面更换政策
先决条件 - 页面替换算法
除了 LRU、OPT 和 FIFO 页面替换策略,我们还有第二次机会/时钟页面替换策略。在Second Chance页面替换策略中,被移除的候选页面在轮询事项中被考虑,并且在连续考虑之间已经被访问的页面不会被替换。被替换的页面是在循环问题中考虑时自上次考虑以来尚未被访问的页面。
它可以通过向每个内存帧添加一个“第二次机会”位来实现——每次考虑该帧时(由于对其中的页面进行了引用),该位设置为 1,这为页面提供了第二次机会,当我们考虑要替换的候选页面时,我们将第一个页面替换为该位设置为 0(同时将我们在此过程中看到的其他页面的位清零)。因此,“第二次机会”位设置为 1 的页面在第一次考虑期间永远不会被替换,并且只有在所有其他页面也应该有第二次机会时才会被替换!
例子 -
假设参考字符串是0 4 1 4 2 4 3 4 2 4 0 4 1 4 2 4 3 4并且我们有3帧。让我们通过跟踪第二次机会位和指针来看看算法是如何进行的。
- 最初,所有帧都是空的,因此在前 3 次传递后,它们将填充 {0, 4, 1},第二次机会数组将为 {0, 0, 0},因为尚未引用任何帧。此外,指针将循环回到 0。
- Pass-4: Frame={0, 4, 1}, second_chance = {0, 1, 0} [4 will get a second chance], pointer = 0 (不需要更新页面,所以候选人仍然是页面中的页面0), pf = 3(缺页错误数没有增加)。
- Pass-5: Frame={2, 4, 1}, second_chance= {0, 1, 0} [0 替换;它的第二次机会位是 0,所以它没有第二次机会],指针=1(更新),pf=4
- Pass-6: Frame={2, 4, 1}, second_chance={0, 1, 0}, pointer=1, pf=4 (无变化)
- Pass-7: Frame={2, 4, 3}, second_chance= {0, 0, 0} [4 幸存了,但它的第二次机会位变成了 0],pointer=0(因为索引 2 的元素最终被替换了),pf =5
- Pass-8: frame={2, 4, 3}, second_chance= {0, 1, 0} [4 再次引用], pointer=0, pf=5
- Pass-9: frame={2, 4, 3}, second_chance= {1, 1, 0} [2 再次引用], pointer=0, pf=5
- Pass-10: Frame={2, 4, 3}, second_chance= {1, 1, 0}, pointer=0, pf=5 (无变化)
- Pass-11: Frame={2, 4, 0}, second_chance= {0, 0, 0}, pointer=0, pf=6 (2 和 4 获得第二次机会)
- Pass-12: Frame={2, 4, 0}, second_chance= {0, 1, 0}, pointer=0, pf=6 (4 将再次获得第二次机会)
- Pass-13: frame={1, 4, 0}, second_chance= {0, 1, 0}, pointer=1, pf=7 (pointer updated, pf updated)
- 第 14 页: Frame={1, 4, 0},second_chance= {0, 1, 0},pointer=1,pf=7(无变化)
- 第 15 页: Frame={1, 4, 2},second_chance= {0, 0, 0},pointer=0,pf=8(4 由于第二次机会再次存活!)
- 第 16 页: Frame={1, 4, 2},second_chance= {0, 1, 0},pointer=0,pf=8(第二次机会更新)
- 第 17 页: frame={3, 4, 2},second_chance= {0, 1, 0},pointer=1,pf=9(pointer,pf 更新)
- 第 18 页: Frame={3, 4, 2},second_chance= {0, 1, 0},pointer=1,pf=9(无变化)
在这个例子中,第二次机会算法和 LRU 方法一样好,后者在硬件中实现的成本要高得多。
更多例子——
Input: 2 5 10 1 2 2 6 9 1 2 10 2 6 1 2 1 6 9 5 1
3
Output: 14
Input: 2 5 10 1 2 2 6 9 1 2 10 2 6 1 2 1 6 9 5 1
4
Output: 11
算法 -
创建一个数组frame来跟踪当前内存中的页面,另一个布尔数组second_chance来跟踪该页面自上次替换后是否被访问过(即是否值得第二次机会)和一个变量指针来跟踪替换目标.
- 开始遍历数组arr 。如果页面已经存在,只需将其在second_chance 中的对应元素设置为 true 并返回。
- 如果页面不存在,检查指针指向的空间是否为空(表示缓存尚未满)——如果是,我们将元素放在那里并返回,否则我们将遍历数组arr一个(循环使用pointer的值),将所有对应的second_chance元素标记为 false,直到我们找到一个已经是 false 的元素。这是最适合替换的页面,所以我们这样做并返回。
- 最后,我们报告页面错误计数。
C++
// CPP program to find largest in an array
// without conditional/bitwise/ternary/ operators
// and without library functions.
#include
#include
#include
using namespace std;
// If page found, updates the second chance bit to true
static bool findAndUpdate(int x,int arr[],
bool second_chance[],int frames)
{
int i;
for(i = 0; i < frames; i++)
{
if(arr[i] == x)
{
// Mark that the page deserves a second chance
second_chance[i] = true;
// Return 'true', that is there was a hit
// and so there's no need to replace any page
return true;
}
}
// Return 'false' so that a page for replacement is selected
// as he reuested page doesn't exist in memory
return false;
}
// Updates the page in memory and returns the pointer
static int replaceAndUpdate(int x,int arr[],
bool second_chance[],int frames,int pointer)
{
while(true)
{
// We found the page to replace
if(!second_chance[pointer])
{
// Replace with new page
arr[pointer] = x;
// Return updated pointer
return (pointer + 1) % frames;
}
// Mark it 'false' as it got one chance
// and will be replaced next time unless accessed again
second_chance[pointer] = false;
//Pointer is updated in round robin manner
pointer = (pointer + 1) % frames;
}
}
static void printHitsAndFaults(string reference_string,
int frames)
{
int pointer, i, l=0, x, pf;
//initially we consider frame 0 is to be replaced
pointer = 0;
//number of page faults
pf = 0;
// Create a array to hold page numbers
int arr[frames];
// No pages initially in frame,
// which is indicated by -1
memset(arr, -1, sizeof(arr));
// Create second chance array.
// Can also be a byte array for optimizing memory
bool second_chance[frames];
// Split the string into tokens,
// that is page numbers, based on space
string str[100];
string word = "";
for (auto x : reference_string)
{
if (x == ' ')
{
str[l]=word;
word = "";
l++;
}
else
{
word = word + x;
}
}
str[l] = word;
l++;
// l=the length of array
for(i = 0; i < l; i++)
{
x = stoi(str[i]);
// Finds if there exists a need to replace
// any page at all
if(!findAndUpdate(x,arr,second_chance,frames))
{
// Selects and updates a victim page
pointer = replaceAndUpdate(x,arr,
second_chance,frames,pointer);
// Update page faults
pf++;
}
}
cout << "Total page faults were " << pf << "\n";
}
// Driver code
int main()
{
string reference_string = "";
int frames = 0;
// Test 1:
reference_string = "0 4 1 4 2 4 3 4 2 4 0 4 1 4 2 4 3 4";
frames = 3;
// Output is 9
printHitsAndFaults(reference_string,frames);
// Test 2:
reference_string = "2 5 10 1 2 2 6 9 1 2 10 2 6 1 2 1 6 9 5 1";
frames = 4;
// Output is 11
printHitsAndFaults(reference_string,frames);
return 0;
}
// This code is contributed by NikhilRathor
Java
// Java program to find largest in an array
// without conditional/bitwise/ternary/ operators
// and without library functions.
import java.util.*;
import java.io.*;
class secondChance
{
public static void main(String args[])throws IOException
{
String reference_string = "";
int frames = 0;
//Test 1:
reference_string = "0 4 1 4 2 4 3 4 2 4 0 4 1 4 2 4 3 4";
frames = 3;
//Output is 9
printHitsAndFaults(reference_string,frames);
//Test 2:
reference_string = "2 5 10 1 2 2 6 9 1 2 10 2 6 1 2 1 6 9 5 1";
frames = 4;
//Output is 11
printHitsAndFaults(reference_string,frames);
}
//If page found, updates the second chance bit to true
static boolean findAndUpdate(int x,int arr[],
boolean second_chance[],int frames)
{
int i;
for(i = 0; i < frames; i++)
{
if(arr[i] == x)
{
//Mark that the page deserves a second chance
second_chance[i] = true;
//Return 'true', that is there was a hit
//and so there's no need to replace any page
return true;
}
}
//Return 'false' so that a page for replacement is selected
//as he reuested page doesn't exist in memory
return false;
}
//Updates the page in memory and returns the pointer
static int replaceAndUpdate(int x,int arr[],
boolean second_chance[],int frames,int pointer)
{
while(true)
{
//We found the page to replace
if(!second_chance[pointer])
{
//Replace with new page
arr[pointer] = x;
//Return updated pointer
return (pointer+1)%frames;
}
//Mark it 'false' as it got one chance
// and will be replaced next time unless accessed again
second_chance[pointer] = false;
//Pointer is updated in round robin manner
pointer = (pointer+1)%frames;
}
}
static void printHitsAndFaults(String reference_string,
int frames)
{
int pointer,i,l,x,pf;
//initially we consider frame 0 is to be replaced
pointer = 0;
//number of page faults
pf = 0;
//Create a array to hold page numbers
int arr[] = new int[frames];
//No pages initially in frame,
//which is indicated by -1
Arrays.fill(arr,-1);
//Create second chance array.
//Can also be a byte array for optimizing memory
boolean second_chance[] = new boolean[frames];
//Split the string into tokens,
//that is page numbers, based on space
String str[] = reference_string.split(" ");
//get the length of array
l = str.length;
for(i = 0; i
Python3
# Python3 program to find largest in an array
# without conditional/bitwise/ternary/ operators
# and without library functions.
# If page found, updates the second chance bit to true
def findAndUpdate(x, arr, second_chance, frames):
for i in range(frames):
if arr[i] == x:
# Mark that the page deserves a second chance
second_chance[i] = True
# Return 'true', that is there was a hit
#and so there's no need to replace any page
return True
# Return 'false' so that a page
# for replacement is selected
# as he reuested page doesn't
# exist in memory
return False
# Updates the page in memory
# and returns the pointer
def replaceAndUpdate(x, arr, second_chance, frames, pointer):
while(True):
# We found the page to replace
if not second_chance[pointer]:
# Replace with new page
arr[pointer] = x
#Return updated pointer
return (pointer+1)%frames
# Mark it 'false' as it got one chance
# and will be replaced next time unless accessed again
second_chance[pointer] = False
# Pointer is updated in round robin manner
pointer = (pointer + 1) % frames
def printHitsAndFaults(reference_string, frames):
# initially we consider
# frame 0 is to be replaced
pointer = 0
# number of page faults
pf = 0
# Create a array to hold page numbers
arr = [0]*frames
# No pages initially in frame,
# which is indicated by -1
for s in range(frames):
arr[s] = -1
# Create second chance array.
# Can also be a byte array for optimizing memory
second_chance = [False]*frames
# Split the string into tokens,
# that is page numbers, based on space
Str = reference_string.split(' ')
# get the length of array
l = len(Str)
for i in range(l):
x = Str[i]
# Finds if there exists a need to replace
# any page at all
if not findAndUpdate(x,arr,second_chance,frames):
# Selects and updates a victim page
pointer = replaceAndUpdate(x,arr,second_chance,frames,pointer)
# Update page faults
pf += 1
print("Total page faults were", pf)
reference_string = ""
frames = 0
# Test 1:
reference_string = "0 4 1 4 2 4 3 4 2 4 0 4 1 4 2 4 3 4"
frames = 3
# Output is 9
printHitsAndFaults(reference_string,frames)
# Test 2:
reference_string = "2 5 10 1 2 2 6 9 1 2 10 2 6 1 2 1 6 9 5 1"
frames = 4
# Output is 11
printHitsAndFaults(reference_string,frames)
# This code is contributed by mukesh07.
C#
// C# program to find largest in an array
// without conditional/bitwise/ternary/ operators
// and without library functions.
using System;
public class secondChance
{
public static void Main()
{
String reference_string = "";
int frames = 0;
// Test 1:
reference_string = "0 4 1 4 2 4 3 4 2 4 0 4 1 4 2 4 3 4";
frames = 3;
// Output is 9
printHitsAndFaults(reference_string,frames);
// Test 2:
reference_string = "2 5 10 1 2 2 6 9 1 2 10 2 6 1 2 1 6 9 5 1";
frames = 4;
// Output is 11
printHitsAndFaults(reference_string,frames);
}
// If page found, updates the second chance bit to true
static bool findAndUpdate(int x,int []arr,
bool []second_chance,int frames)
{
int i;
for(i = 0; i < frames; i++)
{
if(arr[i] == x)
{
//Mark that the page deserves a second chance
second_chance[i] = true;
//Return 'true', that is there was a hit
//and so there's no need to replace any page
return true;
}
}
// Return 'false' so that a page
// for replacement is selected
// as he reuested page doesn't
// exist in memory
return false;
}
// Updates the page in memory
// and returns the pointer
static int replaceAndUpdate(int x,int []arr,
bool []second_chance,int frames,int pointer)
{
while(true)
{
//We found the page to replace
if(!second_chance[pointer])
{
//Replace with new page
arr[pointer] = x;
//Return updated pointer
return (pointer+1)%frames;
}
//Mark it 'false' as it got one chance
// and will be replaced next time unless accessed again
second_chance[pointer] = false;
//Pointer is updated in round robin manner
pointer = (pointer + 1) % frames;
}
}
static void printHitsAndFaults(String reference_string,
int frames)
{
int pointer, i, l, x, pf;
// initially we consider
// frame 0 is to be replaced
pointer = 0;
// number of page faults
pf = 0;
// Create a array to hold page numbers
int []arr = new int[frames];
// No pages initially in frame,
// which is indicated by -1
for(int s = 0;s
Javascript
输出:
Total page faults were 9
Total page faults were 11
笔记:
- 数组arr和second_chance可以通过哈希图(元素作为键,真/假作为值)替换和组合在一起以加快搜索速度。
- 这种方法的时间复杂度是O(Number_of_frames*reference_string_length)或O(mn)但由于帧数在操作系统中是一个常数(因为主内存大小是固定的),它只是O(n) [与 hashmap 相同方法,但这将具有较低的常数]
- 第二次机会算法可能会受到 Belady 异常的影响。