在地址映射过程中,若在页面中发现所要访问的页面不再内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。
页面置换算法有很多种,比如Optimal(最佳置换)算法,FIFO(先进先出)算法,LRU(最近最久未使用)算法等等,最佳置换算法是不实际的,它只是一种构想,因为我们并不能预测哪个页面在将来再也不会被使用。那么对于FIFO算法和LRU算法那个更好呢?这就涉及到一个概念---“缺页率”。在进程的运行过程中,若其所要访问的页面不在内存中则缺页。我们不能让缺页率太高,所以必须选择一种使得缺页率较小的置换算法。
FIFO算法实现简单,但是性能较差,因为它依据的条件是各个页面调入内存的时间,而页面调入的先后并不能反映页面的使用情况,LRU算法,是根据页面调入内存后的使用情况进行决策的,由于我们是无法预知页面将来的使用情况,只能利用“最近的过去”作为“最近的将来”的近似,所以LRU算法选择了内存中最久没有被使用到的页面进行淘汰。
该算法赋予每一个页面一个访问字段,用来记录一个页面自上次被访问所经历的时间t。当产生缺页的时候,选择现有页面中t值最大的,即最近最久未使用的页面进行淘汰。
有如下例子
为了实现此算法,我们用java里面的ArrayList来模拟操作系统中的页面缓冲区,将页面放在里面,输入一个页面访问序列,在缓冲区中进行页面的置换。
1、首先我们定义页面属性,有页面编号和页面的时间t
package LRU;
public class Page {
char num;//页面编号
int time;//页面没有被访问到的时长
}
2、然后进行页面置换算法:
package LRU;
import java.util.ArrayList;
import java.util.Scanner;
public class LRU {
static ArrayList<Page> pages = new ArrayList<Page>();//模拟缓冲区的队列
int size = 4;//设置缓冲区大小为4个页面
public static void main(String[] args) {
LRU lru = new LRU();
lru.initList();
System.out.println("当前缓冲区大小"+lru.size+"\n缓冲区状态为:");
lru.printList();
lru.getPages();
}
/**
* 得到要置换的所有页面序列
*/
private void getPages() {
String str = null;
System.out.println("请输入页面序列");
Scanner sca = new Scanner(System.in);
str = sca.next();
toChars(str);
}
/**
* 将序列序号存入char型数组
*
* @param str
*/
private void toChars(String str) {
char[] ch = new char[str.length() + 1];
for (int i = 0; i < str.length(); i++) {
ch[i] = str.charAt(i);
}
ch[str.length()] = '#';
exchange(ch);
}
/**
* 初始化缓冲区(cache)
*/
private void initList() {
for (int i = 0; i < size; i++) {
Page page = new Page();
page.num = '#';
page.time = 0;
pages.add(page);
}
}
private void exchange(char[] ch) {
char temp;
int time = 0;
int i = 0;
printList();
while (ch[i] != '#') {
if(i<9){
System.out.print("\n"+"第"+0+(i+1)+"次置换----");
}
else{System.out.print("\n"+"第"+(i+1)+"次置换----");}
if (isIn(ch[i]) != -1) {
System.out.print("当前页面存在缓冲区:");
int position = isIn(ch[i]);
pages.get(position).time = 0;
timeAdd(position);
printList();
i++;
continue;
}
if (space(ch[i]) != -1) {
System.out.print("缓冲区内有空余页面:");
int position = space(ch[i]);
pages.get(position).num = ch[i];
pages.get(position).time = 0;
timeAdd(position);
printList();
i++;
continue;
}
if (isIn(ch[i]) == -1) {
System.out.print("当前页面不在缓冲区:");
int max = 0;
int position = 0;
for (int j = 0; j < size; j++) {
if (pages.get(j).time > max) {
max = pages.get(j).time;
position = j;
}
}
pages.get(position).num = ch[i];
pages.get(position).time = 0;
timeAdd(position);
printList();
i++;
continue;
}
}
}
/**
* 判断缓冲区是否有空位
* @param ch
* @return
*/
private int space(char ch) {
int flag = -1;
for (int i = 0; i < size; i++) {
if (pages.get(i).num != '#') {
continue;
}
flag = i;
break;
}
return flag;
}
/**
* 判断当前页面有没有在缓冲区内,返回位置
* @param ch
* @return
*/
private int isIn(char ch) {
int flag = -1;
for (int i = 0; i < size; i++) {
if (ch != pages.get(i).num) {
continue;
}
flag = i;
break;
}
return flag;
}
/**
* 打印缓冲区页面
*/
private void printList() {
for (int i = 0; i < size; i++) {
System.out.print(pages.get(i).num + "\t");
}
}
/**
* 增加页面时间属性
* @param position
*/
private void timeAdd(int position) {
for (int i = 0; i < size; i++) {
if (i == position || pages.get(i).num == '#') {
continue;
}
pages.get(i).time += 1;
}
}
}
运行结果如下: