LFU:最不经常使用(最少次)淘汰算法(Least Frequently Used)。LFU是淘汰一段时间内,使用次数最少的页面。
package HomeWork_OS.LRU;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class LFU_os {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入存储区块数: ");
int userInput = sc.nextInt();
int[] brickArr = new int[userInput]; //元素默认都为0
int indexNum = 1;
StringBuffer sb = new StringBuffer();
System.out.println("请输入页号走向(输入0结束): ");
while(userInput!= 0){
System.out.print("页面序号" +indexNum + ": " );
userInput = sc.nextInt();
sb.append(userInput);
indexNum++;
}
System.out.println("输入结束" +
"\n置换情况如下: ");
// System.out.println("sb = " + sb.toString());
String str = sb.toString();
char arr1[] = str.toCharArray(); //将用户输入转换成字符串数组
//页面数组
int[][] arr = new int[(arr1.length)][2];
// System.out.println("arr1.length = " + arr1.length);
// System.out.println("arr.length = " + arr.length);
// System.out.println("打印arr1 " + Arrays.toString(arr1));
// System.out.println("indexArr1 = " + indexArr1);
double pageFaultRate; //缺页率
int pageNum = arr1.length - 1; //总页面数
int pageFaultCount = 0; //缺页次数
int pageIndex = 1;//页面序号
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (j == 0 ){ //二维数组第一项存页面序号
arr[i][j] = pageIndex++;
}else{ //二维数组第二项存页号
arr[i][j] = Integer.parseInt(String.valueOf(arr1[i])); //将字符串数组转换成整型数组,存入到二维数组每一行的第二项中
}
}
}
//打印页面数组
/* System.out.println("打印页面数组:");
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (j == 0 ){
System.out.print( "页面" + arr[i][j] + " ");
}else{
System.out.println(arr[i][j] );
}
}
}*/
//建立一个存储页面序号和已访问次数的Map集合
//页号为key,访问次数为value
Map<Integer,Integer> map = new HashMap<>();
boolean flagPage;//false 表示元素不存在brickArr中,true 表示存在
for (int k = 0; k < arr.length; k++) { //遍历页面数组
if (arr[k][1] == 0){ //遍历到最后一个元素0的时候退出循环
break;
}
//查找该页面是否存在
Integer getKey = map.get(arr[k][1]);
if (getKey == null){ //如果当前页面不存在map集合中,则添加到该集合中
map.put(arr[k][1],1);
}else { //如果当前页面在map集合中,则将其的值加一
Integer value = map.remove(arr[k][1]) + 1;
map.put(arr[k][1],value);
}
flagPage = false; //设立一个标志位标识存储区块数组中是否存在该元素
for (int i = 0; i < brickArr.length; i++) { //遍历存储区块数组
if(brickArr[i] == 0){ //当存储区块数组中的元素为0时,表示为空,可以直接调入页面
brickArr[i] = arr[k][1];
pageFaultCount++;//缺页次数加一
flagPage = false;
System.out.println("发生缺页中断,但内存中有空闲区," + arr[k][1] +"号页面直接调入!");
break;
}else if (brickArr[i] == arr[k][1]){ //如果存储区块数组中有该元素,则结束内循环,继续遍历页面数组中的下一个元素
flagPage = false;
System.out.println("内存中有" + arr[k][1] + "号页面,无须缺页中断!");
break;
}else{ //如果存储区块数组中没有该元素,将标识位修改为true
flagPage = true;
}
}
if (flagPage){
pageFaultCount++;//缺页次数加一
//找出最近最久未使用的页面替换出去
//存储map中birckArr中的页面号和出现次数
int[][] minCountPage = new int[brickArr.length][2];
//遍历存储区块数组元素
for (int i = 0; i < minCountPage.length; i++) {
Integer getValue = map.get(brickArr[i]); //获取该map元素的值(页面出现的次数)
minCountPage[i][0] = brickArr[i]; //存入最少出现次数页面号
minCountPage[i][1] = getValue; //存入最少出现次数页面次数
}
//获取出现次数最小的页面值和页面号
//赋数组最后的数为默认最小值
int minPageValue = minCountPage[0][1],minPageNumKey = minCountPage[0][0];
for (int i = 1; i < minCountPage.length; i++) {
if (minPageValue > minCountPage[i][1]){
minPageValue = minCountPage[i][1];
minPageNumKey = minCountPage[i][0];//获取最小value的页面号
}
}
//获取存储区块数组中历史出现次数最少的页面,在存储区块数组中的索引
int brickArrMinPageIndex = 0;
for (int i = 1; i < brickArr.length; i++) {
if (brickArr[i] == minPageNumKey){
brickArrMinPageIndex = i;
break;
}
}
System.out.println("发生缺页中断,将" + brickArr[brickArrMinPageIndex] + "号页面调出," +
arr[k][1] + "号装入!");
//存储区块数组中元素挪动替换
for (int i = 0; i < brickArr.length; i++) {
//将当前要添加的页面放到存储区块数组最后
if (i == brickArr.length - 1){
brickArr[i] = arr[k][1];
}else if (i >= brickArrMinPageIndex){
brickArr[i] = brickArr[i + 1];
}else
continue;
}
}
/*打印存储区块数数组*/
/* System.out.print("打印brickArr: ");
for (int i : brickArr) {
System.out.print(i + " ");
}
System.out.println();
System.out.println("遍历map:");
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.print ("key:" + key + " value: "+ value + "\n");
}
System.out.println();*/
}
pageFaultRate = (double)pageFaultCount / pageNum * 100; //缺页率
System.out.println("页号" + pageNum +
"个,缺页中断" + pageFaultCount +
"次,缺页率:" + String.format("%.4f",pageFaultRate) +
"%");
}
}
程序调试:
调试一:
请输入存储区块数:3
请输入页号走向(输入0结束):
页面序号1: 4
页面序号2: 3
页面序号3: 2
页面序号4: 1
页面序号5: 4
页面序号6: 3
页面序号7: 5
页面序号8: 4
页面序号9: 3
页面序号10: 2
页面序号11: 1
页面序号12: 5
页面序号13: 0
输入结束!
置换情况如下:
发生缺页中断,但内存中有空闲区,4号页面直接调入!400
发生缺页中断,但内存中有空闲区,3号页面直接调入!430
发生缺页中断,但内存中有空闲区,2号页面直接调入!432
发生缺页中断,将4号页面调出,1号装入!321
发生缺页中断,将3号页面调出,4号装入!214
发生缺页中断,将2号页面调出,3号装入!143
发生缺页中断,将1号页面调出,5号装入!435
内存中有4号页面,无须缺页中断!435
内存中有3号页面,无须缺页中断!435
发生缺页中断,将5号页面调出,2号装入!432
发生缺页中断,将4号页面调出,1号装入!321
发生缺页中断,将3号页面调出,5号装入!215
页号12个,缺页中断10次,缺页率:83.3333%
调试二:
请输入存储区块数:4
请输入页号走向(输入0结束):
页面序号1: 4
页面序号2: 3
页面序号3: 2
页面序号4: 1
页面序号5: 4
页面序号6: 3
页面序号7: 5
页面序号8: 4
页面序号9: 3
页面序号10: 2
页面序号11: 1
页面序号12: 5
页面序号13: 0
输入结束!
置换情况如下:
发生缺页中断,但内存中有空闲区,4号页面直接调入!
发生缺页中断,但内存中有空闲区,3号页面直接调入!
发生缺页中断,但内存中有空闲区,2号页面直接调入!
发生缺页中断,但内存中有空闲区,1号页面直接调入!
内存中有4号页面,无须缺页中断!
内存中有3号页面,无须缺页中断!
发生缺页中断,将2号页面调出,5号装入!
内存中有4号页面,无须缺页中断!
内存中有3号页面,无须缺页中断!
发生缺页中断,将3号页面调出,2号装入!
发生缺页中断,将5号页面调出,1号装入!
发生缺页中断,将4号页面调出,5号装入!
页号12个,缺页中断8次,缺页率:66.6667%