存储管理的主要功能之一是合理地分配空间。请求页式管理是一种常用的虚拟存储管理技术。
这次的目的是通过请求页式管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换算法。
要求如下
(1)
通过计算不同算法的命中率比较算法的优劣。同时也考虑了用户内存 容量对命中率的影响。 命中率 1 页面失效次数 页地址流长度 页面失效次数为每次访问相应指令时,该指令所对应的页不在内存中 的次数。 在本实验中,假定页面大小为 1k,用户虚存容量为 32k,用户内存容 量为 4 页到 32 页。 (2) produce_addstream 通过随机数产生一个指令序列,共 320 条指令。 A、 指令的地址按下述原则生成: 1) 50%的指令是顺序执行的 2)25%的指令是均匀分布在前地址部分 3) 25%的指令是均匀分布在后地址部分 10 B、 具体的实施方法是: 1) 在[0,319]的指令地址之间随机选取一起点 m; 2) 顺序执行一条指令,即执行地址为 m+1 的指令; 3) 在前地址[0,m+1]中随机选取一条指令并执行,该指令的地 址为 m’; 4) 顺序执行一条指令,地址为 m’+1 的指令 5) 在后地址[m’+2,319]中随机选取一条指令并执行; 6) 重复上述步骤 1)~5),直到执行 320 次指令 C、 将指令序列变换称为页地址流 在用户虚存中,按每 k 存放 10 条指令排列虚存地址,即 320 条指令在 虚存中的存放方式为: 第 0 条~第 9 条指令为第 0 页(对应虚存地址为[0,9]); 第 10 条~第 19 条指令为第 1 页(对应虚存地址为[10,19]); 。。。。。。 第 310 条~第 319 条指令为第 31 页(对应虚存地址为[310,319]); 按以上方式,用户指令可组成 32 页。 (3)计算并输出下属算法在不同内存容量下的命中率。 1)先进先出的算法(FIFO); 2)最近最少使用算法(LRU); 3)最佳淘汰算法(OPT); 4)最少访问页面算法(LFR);
下面给出Java代码的实现
import java.util.*; public class A { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("Start memory management.\r\n"+"Producing address flow, wait for while, please. "); produce_addstream(); for(int a:stream) { System.out.print(a+" "); } System.out.println("\r\nThere are algorithms in the program \r\n1、 Optimization algorithm\r\n" + "2、 Least recently used algorithm\r\n" + "3、 First in first out algorithm\r\n" + "4、 Least frequently used algorithm Select an algorithm number, please.\r\n"); int Num = sc.nextInt(); switch(Num) { case 3: FIFO(3); break; case 2: LRU(3); break; case 1: OPT(3); break; case 4: LFU(3); break; default: System.out.println("there is not the algorithm in the program"); break; } System.out.println("do you try again with anther algorithm(y/n)"); for(int i=2;i<32;i++) { System.out.println("---Msize="+i+"------"); FIFO(i); LRU(i); OPT(i); LFU(i); } } static List<Integer> stream; /** * @return 产生指令序列stream */ public static void produce_addstream(){ stream=new ArrayList<>(); do { int m = (int)((Math.random()*319));//起点 stream.add(m+1);//执行m+1 int m2 = (int)((Math.random()*(m+1))); stream.add(m2);//执行m2 stream.add(m2+1);//执行m2+1 int m3 = (m2+2)+(int)(+Math.random()*(319-m2-2)); stream.add(m3);//执行[m2+2,319] }while(stream.size()<=320); } /** * 根据指令数找到页面 * @param zhiLing 所需指令 * @return 指令所在页面 */ public static int search(int zhiLing) { return zhiLing/10; } /** * 先进先出 * @param Msize 物理块数 */ public static void FIFO(int Msize) { Queue<Integer> que = new LinkedList<>(); Double C = 0.0;//未命中次数 for(int i=0;i<stream.size();i++) { int zhiLing = stream.get(i); int yeMian = search(zhiLing); if(que.contains(yeMian)) { }else { C++; if(que.size()==Msize) { que.poll(); } que.offer(yeMian); } } C-=Msize; Double c = 1-(double) (C/320); System.out.println("FIFO: "+String.format("%.6f",c)+" Msize : "+Msize); } /** * 最近最久未使用算法 * @param Msize 物理块 */ public static void LRU(int Msize) { Stack<Integer> stack = new Stack<>(); Double C = 0.0;//未命中次数 for(int i=0;i<stream.size();i++) { int zhiLing = stream.get(i); int yeMian = search(zhiLing); if(stack.contains(yeMian)) { stack.removeElement(yeMian); stack.push(yeMian); }else { C++; if(stack.size()==Msize) { stack.removeElement(stack.firstElement()); } stack.push(yeMian); } } C-=Msize; Double c = 1-(double) (C/320); System.out.println("LRU : "+String.format("%.6f",c)+" Msize : "+Msize); } /** * 最佳置换算法 * @param Msize 物理块 */ public static void OPT(int Msize) { Double C = 0.0;//未命中次数 Set<Integer> set = new HashSet<>(); for(int i=0;i<stream.size();i++) { int zhiLing = stream.get(i); int yeMian = search(zhiLing); if(set.contains(yeMian)) { }else { C++; if(set.size()==Msize) { int max = -1;//最长时间不会使用的指令的页面 int[] temp = new int[32]; for(int a:set) { for(int j=i+1;j<stream.size();j++) { if(search(stream.get(j))==a) { temp[a]=j; break; } } } for(int a:set) { if(max==-1) max=a; if(temp[a]==0) { set.remove(a); break; } if(temp[a]>temp[max]) max=a; } if(set.size()==Msize) { set.remove(max);//移除该页面 } } set.add(yeMian); } } C-=Msize; Double c = 1-(double) (C/320); System.out.println("OPT : "+String.format("%.6f",c)+" Msize : "+Msize); } /** * 最少使用置换算法 * @param Msize */ public static void LFU(int Msize) { Double C = 0.0;//未命中次数 Set<Integer> set = new HashSet<>(); for(int i=0;i<stream.size();i++) { int zhiLing = stream.get(i); int yeMian = search(zhiLing); int[] temp = new int[32]; if(set.contains(yeMian)) { }else { C++; if(set.size()==Msize) { int Min = -1; for(int a:set) { for(int j=i-1;j>=0;j--) { if(search(stream.get(j))==a) { temp[a]=j; break; } } } for(int a:set) { if(Min==-1) { Min=a; continue; } if(temp[a]<temp[Min]) { Min=a; } } set.remove(Min);//移除该页面 } set.add(yeMian); temp[yeMian]++; } } C-=Msize; Double c = 1-(double) (C/320); System.out.println("LFU : "+String.format("%.6f",c)+" Msize : "+Msize); } }
(1) 通过计算不同算法的命中率比较算法的优劣。同时也考虑了用户内存
容量对命中率的影响。
命中率 =1- |
页面失效次数 |
|
页地址流长度 |
|
|
|
|
页面失效次数为每次访问相应指令时,该指令所对应的页不在内存中
的次数。
在本实验中,假定页面大小为 1k,用户虚存容量为 32k,用户内存容
量为 4页到 32页。
(2) produce_addstream 通过随机数产生一个指令序列,共 320 条指令。
A、指令的地址按下述原则生成:
1) 50%的指令是顺序执行的
2)25%的指令是均匀分布在前地址部分
3) 25%的指令是均匀分布在后地址部分
10
1) 在[0,319]的指令地址之间随机选取一起点 m;
2) 顺序执行一条指令,即执行地址为 m+1的指令;
3) 在前地址[0,m+1]中随机选取一条指令并执行,该指令的地
址为 m’;
4) 顺序执行一条指令,地址为 m’+1的指令
5) 在后地址[m’+2,319]中随机选取一条指令并执行;
6) 重复上述步骤 1)~5),直到执行 320次指令
C、 将指令序列变换称为页地址流
在用户虚存中,按每 k存放 10条指令排列虚存地址,即 320条指令在
虚存中的存放方式为:
第 0条~第 9条指令为第 0页(对应虚存地址为[0,9]);
第 10 条~第 19 条指令为第 1 页(对应虚存地址为[10,19]);
。。。。。。
第 310 条~第 319 条指令为第 31 页(对应虚存地址为[310,319]);
按以上方式,用户指令可组成 32页。
(3)计算并输出下属算法在不同内存容量下的命中率。
1)先进先出的算法(FIFO);
2)最近最少使用算法(LRU);
3)最佳淘汰算法(OPT);
4)最少访问页面算法(LFR);