頁面置換算法(OPT,FIFO,LRU,CLOCK)


1、最佳淘汰算法(OPT)   
2、先進先出的算法(FIFO)
3、最近最久未使用算法(LRU)  
4、簡單時鐘(鐘錶)算法(CLOCK)  
命中率=1-頁面失效次數/頁地址流(序列)長度
缺頁率=缺頁次數/(缺頁次數+訪問成功次數)

1、最佳淘汰算法(Optimal)

其所選擇的被淘汰頁面將是以後永不使用的, 或許是在最長(未來)時間內不再被訪問的頁面。 採用最佳置換算法通常可保證獲得最低的缺頁率。但由千人們目前還無法預知,一個進程在內存的若干個頁面中,哪一個頁面是未來最長時間內不再被訪問的,因而該算法是無法實現的, 但可以利用該算法去評價其它算法。

舉例

假定系統爲某進程分配了三個物理塊, 並考慮有以下的頁面號引用串:
7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1
進程運行時,先將7, 0, l三個頁面裝入內存。以後,當進程要訪問頁面2時,將會產生缺頁中斷。此時OS根據最佳置換算法將選擇頁面7予以淘汰。這是因爲頁面0將作爲第5個被訪問的頁面,頁面1是第14個被訪問的頁面,而頁面7則要在第18次頁面訪問時才需調入。七次訪問頁面0時,因它已在內存而不必產生缺頁中斷。當進程訪問頁面3時,又將引起頁面l被淘汰;因爲,它在現有的1, 2, 0三個頁面中,將是以後最晚才被訪問的。 圖示採用最佳置換算法時的置換圖。由圖可看出,採用最佳置換算法發生了6次頁面置換。
在這裏插入圖片描述

代碼

#include <stdio.h>
#include<iostream>
#include <string>
#include<stdlib.h>
#include <ctype.h>
#include<algorithm>
using namespace std;
#define ERROR -1 
int page[1000];//內存
int toppage;
int MAXSIZE;
int F, ch;//缺頁次數,置換次數
void watch(){//查看當前內存中存有的頁面號
	printf("當前內存序列:");
	for (int i = toppage; i >= 0; i--)
		printf("%d ", page[i]);
	//printf("\t置換次數:%d\t缺頁率:%d%%\n", ch, F * 100 / (S+F));
	printf("\t置換次數:%d\t缺頁次數:%d\n", ch, F);
	return;
}
int locatetime(int queue[], int num, int t, int w){//num是頁面序列總長,t是當前queue頁面序列號,w是當前內存號
	for (int i = t; i <= num; i++){
		if (queue[i] == page[w])return i;
	}
	return num + 1;
}
int Popbase(int queue[], int num, int t){//最久未使用被淘汰,t是queue序列號
	int max=-1,maxid=-1,h;
	for (int i = 0; i <= toppage; i++){
		h=locatetime(queue, num, t,i);
		if (max < h){
			maxid = i;
			max = h;
		}
	}
	return maxid;
}
int search(int a){
	for (int i = toppage; i >= 0; i--){
		if (a == page[i]) return i;
	}
	return ERROR;
}
int scan(char str[], int queue[]){

	int n = strlen(str), j = -1;
	for (int i = 0; i < n; i++){
		if (isdigit(str[i])){
			sscanf(str + i, "%d", &queue[++j]);
			while (isdigit(str[++i]));
			i--;
		}
	}
	return j;//總長度
}
void Optimal(){
	F = 0; ch = 0;
	toppage = -1;
	char str[1000];//輸入字符串
	int t, queue[100];//是否重新出現過,頁地址流
	printf("頁地址流序列:");
	scanf("%s", str);
	int num = scan(str, queue)+1;//頁地址流(序列)長度(0~num,所以長度+1)
	for (int i = 0; i < num; i++){
		t = search(queue[i]);
		if (t != ERROR){//在物理塊中
			printf("不缺頁,無需置換\n");
			continue;
		}
		else{//不在物理塊中
			F++;//物理塊中無,所以缺頁次數+1
			if ((toppage + 1) >= MAXSIZE){//物理塊滿,最佳置換
				//最久未使用被淘汰,被淘汰位置換爲當前序列號
				page[Popbase(queue, num, i)] = queue[i];//i是當前queue序列號
				ch++;//置換次數+1
			}
			else
				page[++toppage] = queue[i];
			
		}
		watch();
	}
	printf("頁地址流長度:%d\t命中率:%d%%\t缺頁率:%d%%\n\n", num, (num - ch) * 100 / num, F * 100 / num);
	fill(page, page + num-1, 0);
}

int main(){
	printf("分配給物理塊的數量:");
	scanf("%d", &MAXSIZE);
	while (MAXSIZE != 0){
		while (MAXSIZE > 1000){
			printf("分配給的物理塊過多,重新分配\n");
			printf("分配給物理塊的數量:");
			scanf("%d", &MAXSIZE);
		}
		Optimal();
		printf("分配給物理塊的數量:");
		scanf("%d", &MAXSIZE);
	}
	system("PAUSE");
	return 0;
}

流程圖

在這裏插入圖片描述
在這裏插入圖片描述

2、先進先出的算法(FIFO)

其所選擇的被淘汰頁面將是以後永不使用的, 或許是在最長(未來)時間內不再被訪問的頁面。 採用最佳置換算法通常可保證獲得最低的缺頁率。但由千人們目前還無法預知,一個進程在內存的若干個頁面中,哪一個頁面是未來最長時間內不再被訪問的,因而該算法是無法實現的, 但可以利用該算法去評價其它算法。

舉例

假定系統爲某進程分配了三個物理塊, 並考慮有以下的頁面號引用串:
7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1
進程運行時,先將7, 0, l三個頁面裝入內存。以後,當進程要訪問頁面2時,將會產生缺頁中斷。此時OS根據最佳置換算法將選擇頁面7予以淘汰。這是因爲頁面0將作爲第5個被訪問的頁面,頁面1是第14個被訪問的頁面,而頁面7則要在第18次頁面訪問時才需調入。七次訪問頁面0時,因它已在內存而不必產生缺頁中斷。當進程訪問頁面3時,又將引起頁面l被淘汰;因爲,它在現有的1, 2, 0三個頁面中,將是以後最晚才被訪問的。 圖示採用最佳置換算法時的置換圖。由圖可看出,採用最佳置換算法發生了6次頁面置換。
在這裏插入圖片描述

代碼

#include <stdio.h>
#include<iostream>
#include <string>
#include<stdlib.h>
#include <ctype.h>
#include<algorithm>
using namespace std;
#define ERROR -1 
int page[1000];//內存
int toppage;
int MAXSIZE;
int time;//最長駐留的page的序號
int F, ch;//缺頁次數,置換次數
void watch(){//查看當前內存中存有的頁面號
	printf("當前內存序列:");
	for (int i = toppage; i >= 0; i--)
		printf("%d ", page[i]);
	printf("\t置換次數:%d\t缺頁次數:%d\n", ch, F);
	return;
}
int search(int a){
	for (int i = toppage; i >= 0; i--){
		if (a == page[i]) return i;
	}
	return ERROR;
}
int scan(char str[], int queue[]){

	int n = strlen(str), j = -1;
	for (int i = 0; i < n; i++){
		if (isdigit(str[i])){
			sscanf(str + i, "%d", &queue[++j]);
			while (isdigit(str[++i]));
			i--;
		}
	}
	return j;//總長度
}
void FIFO(){
	F = 0; ch = 0;
	toppage = -1;
	time = 0;
	char str[1000];//輸入字符串
	int t, queue[100];//是否重新出現過,頁地址流
	printf("頁地址流序列:");
	scanf("%s", str);
	int num = scan(str, queue);//頁地址流(序列)長度
	for (int i = 0; i <= num; i++){
		t = search(queue[i]);
		if (t != ERROR){//重複出現過,不缺頁
			printf("不缺頁,無需置換\n");
			continue;
		}
		else{//缺頁
			F++;
			if ((toppage + 1) >= MAXSIZE){//物理塊滿,最先進入的頁面出棧
				page[time] = queue[i];
				time = (time + 1) % MAXSIZE;
				ch++;//置換次數+1
			}
			else//物理塊沒滿,直接置換進內存
				page[++toppage] = queue[i];
			watch();
		}
			
	}
	num++;
	printf("頁地址流長度:%d\t命中率:%d%%\t缺頁率:%d%%\n\n", num, (num - ch) * 100 / num, F * 100 / num);
	fill(page, page + num-1, 0);
}

int main(){
	printf("分配給物理塊的數量:");
	scanf("%d", &MAXSIZE);
	while (MAXSIZE != 0){
		while (MAXSIZE > 1000){
			printf("分配給的物理塊過多,重新分配\n");
			printf("分配給物理塊的數量:");
			scanf("%d", &MAXSIZE);
		}
		FIFO();
		printf("分配給物理塊的數量:");
		scanf("%d", &MAXSIZE);
	}
	system("PAUSE");
	return 0;
}	

流程圖

在這裏插入圖片描述

3、最近最久未使用算法(LRU)

最近最久未使用(LRU)的頁面置換算法是根據頁面調入內存後的使用情況做出決策的。由於無法預測各頁面將來的使用清況,只能利用 “最近的過去” 作爲 “最近的將來” 的近似, 因此,LRU置換算法是選擇最近最久未使用的頁面予以淘汰。 該算法賦予每個頁面一個訪問字段,用來記錄一個頁面自上次被訪問以來所經歷的時間t。 當需淘汰一個頁面時,選擇現有頁面中其t值最大的,即最近最久未使用的頁面予以淘汰。

舉例

當進程第一次對頁面2進行訪問時,由於頁面7是最近最久未被訪問的,故將它置換出去。當進程第一次對頁面3進行訪間時,第1頁成爲最近最久未使用的頁,將它換出。由圖可以看出, 前5個時間的圖像與最佳置換算法時的相同, 但這並非是必然的結果。 因爲最佳置換算法是從 “向後看” 的觀點出發的,即它是依據以後各頁的使用情況進行判斷;而LRU算法則是 “ 向前看” 的,即根據各頁以前的使用情況來判斷, 而頁面過去和未來的走向之間並無必然的聯繫。
在這裏插入圖片描述

代碼

#include <stdio.h>
#include<iostream>
#include <string>
#include<stdlib.h>
#include <ctype.h>
#include<algorithm>
using namespace std;
#define ERROR -1 
int page[1000];//LRU棧
int toppage;
int MAXSIZE;
int F,ch;//缺頁次數,置換次數
void watch(){//查看當前內存中存有的頁面號
	printf("當前內存序列:");
	for (int i = toppage; i >= 0; i--)
		printf("%d ", page[i]);
	printf("\t置換次數:%d\t缺頁次數:%d\n",ch,F);
	return;
}
void Popbase(int a){//page[a]出棧
	for (int i = (a+1); i <= toppage; i++){
		page[i - 1] = page[i];
	}
	toppage--;
	return;
}
int search(int a){
	for (int i = toppage; i >= 0; i--){
		if (a == page[i]) return i;
	}
	return ERROR;
}
int scan(char str[],int queue[]){
	
	int n = strlen(str),j=-1;
	for (int i = 0; i < n; i++){
		if (isdigit(str[i])){
			sscanf(str + i, "%d", &queue[++j]);
			while (isdigit(str[++i]));
			i--;
		}
	}
	return j;//總長度
}
void LRU(){
	F = 0; ch = 0;
	toppage = -1;
	char str[1000];//輸入字符串
	int t,queue[100];//是否重新出現過,頁地址流
	printf("頁地址流序列:");
	scanf("%s", str);
	int num=scan(str, queue);//頁地址流(序列)長度
	for(int i=0;i<=num;i++){
		t = search(queue[i]);
		if (t != ERROR){//重複出現過,不缺頁
			Popbase(t);//重複出現的page[t]先出棧
		}
		else{//缺頁
			F++;//缺頁次數+1
			if ((toppage + 1) >= MAXSIZE){//物理塊滿,最近最久未使用的頁面出棧
				Popbase(0);//最近最久未使用的頁面是page[0],出棧
				ch++;//置換次數+1
			}
		}
		page[++toppage] = queue[i];
		watch();
	}
	num++;
	printf("頁地址流長度:%d\t命中率:%d%%\t缺頁率:%d%%\n\n", num, (num - ch) * 100 / num, F * 100 / num);
	fill(page, page + num - 1,0);
}

int main(){
	printf("分配給物理塊的數量:");
	scanf("%d", &MAXSIZE);
	while (MAXSIZE != 0){
		while (MAXSIZE > 1000){
			printf("分配給的物理塊過多,重新分配\n");
			printf("分配給物理塊的數量:");
			scanf("%d", &MAXSIZE);
		}
		LRU();
		printf("分配給物理塊的數量:");
		scanf("%d", &MAXSIZE);
	}
	system("PAUSE");
	return 0;
}

流程圖

在這裏插入圖片描述

4、簡單時鐘(鐘錶)算法(CLOCK)

我們把頁面排成一個時鐘的形狀,該時針有一個針臂。每次需要更換頁面的時候,我們從針臂所指的頁面開始 檢查。如果當前頁面的訪問位爲0,即從上次檢查到這次,若該頁面沒有被訪問過,將該頁面替換;如果當前頁面的訪問位爲1,即當前頁面被訪問過,那就將其訪問位清零,並順時針移動指針到下一個頁面。

代碼

#include <stdio.h>
#include<iostream>
#include <string>
#include<stdlib.h>
#include<ctype.h>
#include<algorithm>
using namespace std;
#define ERROR -1 
typedef struct CLOCK{
	int data;
	bool fw;
}CLOCK;

int toppage;
int MAXSIZE;
int time;//針臂
int F, ch;//缺頁次數,置換次數
void watch(CLOCK page[]){//查看當前內存中存有的頁面號
	printf("當前內存序列:");
	for (int i = toppage; i >= 0; i--)
		printf("%d ", page[i].data);
	printf("\t置換次數:%d\t缺頁次數:%d\n", ch, F);
	return;
}
int search(int a, CLOCK page[]){
	for (int i = toppage; i >= 0; i--){
		if (a == page[i].data) return i;
	}
	return ERROR;
}
int scan(char str[], int queue[]){

	int n = strlen(str), j = -1;
	for (int i = 0; i < n; i++){
		if (isdigit(str[i])){
			sscanf(str + i, "%d", &queue[++j]);
			while (isdigit(str[++i]));
			i--;
		}
	}
	return j;//總長度
}
void FIFO(){
	CLOCK page[1000];//內存
	F = 0; ch = 0;
	toppage = -1;
	time = 0;//針臂指爲0
	char str[1000];//輸入字符串
	int t, queue[100];//是否重新出現過,頁地址流
	printf("頁地址流序列:");
	scanf("%s", str);
	int num = scan(str, queue);//頁地址流(序列)長度
	for (int i = 0; i <= num; i++){
		t = search(queue[i],page);
		if (t != ERROR){//重複出現過,不缺頁
			printf("不缺頁,無需置換\n");
			continue;
		}
		else{//缺頁
			F++;
			if ((toppage + 1) >= MAXSIZE){//物理塊滿,訪問位爲0的頁面出隊,訪問位爲1的頁面置爲0並訪問下一個直到隊尾
				while (page[time].fw){//訪問位爲1的頁面都賦爲訪問位爲0直到遇到訪問位爲0的
					page[time].fw = false;
					time = (time+1)%MAXSIZE;
				}
				page[time].data = queue[i];
				page[time].fw = true;//訪問位置1
				time = (time + 1) % MAXSIZE;
				ch++;//置換次數+1
			}
			else{//物理塊沒滿,直接置換進內存
				toppage++;
				page[toppage].data = queue[i];
				page[toppage].fw = true;
			}
			watch(page);
		}

	}
	num++;
	printf("頁地址流長度:%d\t命中率:%d%%\t缺頁率:%d%%\n\n", num, (num - ch) * 100 / num, F * 100 / num);

}

int main(){
	printf("分配給物理塊的數量:");
	scanf("%d", &MAXSIZE);
	while (MAXSIZE != 0){
		while (MAXSIZE > 1000){
			printf("分配給的物理塊過多,重新分配\n");
			printf("分配給物理塊的數量:");
			scanf("%d", &MAXSIZE);
		}
		FIFO();
		printf("分配給物理塊的數量:");
		scanf("%d", &MAXSIZE);
	}
	system("PAUSE");
	return 0;
}

流程圖

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章