实验二:虚拟存储管理仿真(6学时)
<一>实验内容:
模拟请求分页虚拟存储管理技术中的硬件地址变换、缺页中断及页式淘汰算法处理缺页中断.
<二>实验目的:
为了使大的作业(其地址空间超过内存可用空间)或多个作业的地址空间之和超过实际主存空间时,仍能运行,引入了”虚拟存储器”的概念.使作业的一部分地址空间在主存,另一部分在辅存,由操作系统实现多级存储的自动管理,实现主存间的自动覆盖.
要求通过本实验,对请求分页管理有一个清楚的概念.
<三>实验题目:
第一部分:模拟请求分页虚拟存储管理技术中的硬件地址变换和缺页中断的过程
提示:
1、 请求分页虚拟存储管理技术是把作业地址空间的全部信息存放在磁盘上,当作业被选中运行时,先把作业的开始几页装入主存并启动运行.为此,在为作业建立页表时,应说明哪些页已在内存,哪些页不在内存.
页表的格式如下:
页号 | 标志 | 主存块号 | 外存地址 |
---|---|---|---|
其中,”标志”表示对应页是否已装入主存
0:表示对应页已装入主存
1:表示对应页未装入主存
“主存块号”表示该页对应的主存块的块号
“外存地址”表示该页所在的外存物理
2、 作业在执行时,指令中的逻辑地址指出参加运算操作数(或指令)地址中的页号和页内偏移量.硬件地址转换机构按页号查页表.
若该页的标志为”1”,则表示该页已在主存,从而找到该页对应的内存块号,根据关系式:
绝对地址=块号*块的长度+页内偏移量
计算出欲访问的内存地址.由于页长为2的整次幂,所以只要将块号与页内偏移量相拼接,放入地址寄存器即可按照该地址取指令或取操作数,完成指定的操作.
若对应的页不在内存(即标志为0),则硬件产生缺页中断,转操作系统处理系统.根据页表中的”外存地址”,找到该页.再查内存分块表,找一个空闲块装入该页,修改页表和内存分块表,继续执行被中断的指令.
3、 设计一个”地址变换”程序,模拟硬件地址变换过程:
当访问的页在内存时,则形成绝对地址后,不去模拟指令的执行,而是输出被转换的地址;当访问的页不在内存时,则输出**”该页(页号)不在内存”,以表示产生了一次缺页中断;若地址非法,显示”地址非法”*,并终止程序的运行.
假定内存的每块长度为128字节,现有一个只有七页的作业,其中第0页至第3页已经装入内存.该作业的页表如下:
页号 | 标志 | 内存块号 | 外存地址 | 修改值 |
---|---|---|---|---|
0 | 1 | 5 | 011 | 1 |
1 | 1 | 8 | 012 | 1 |
2 | 1 | 9 | 013 | 0 |
3 | 1 | 1 | 021 | 0 |
4 | 0 | 022 | ||
5 | 0 | 023 | ||
6 | 0 | 121 |
作业执行的指令序列如下表:
操作 | 页号 | 单元号(八进制) | 操作 | 页号 | 单元号(八进制) |
---|---|---|---|---|---|
+ | 0 | 070 | 移位 | 4 | 053 |
+ | 1 | 050 | + | 5 | 023 |
* | 2 | 015 | 存 | 1 | 037 |
存 | 3 | 021 | 取 | 2 | 076 |
取 | 0 | 057 | + | 4 | 001 |
- | 6 | 040 | 取 | 6 | 084 |
运行你设计的地址变换程序,显示或打印运行结果.因为只是模拟地址变换,并不模拟指令的执行,故不考虑上述指令的操作结果.
第二部分:采用先进先出(或LRU)算法,实现分页管理的缺页调度.
提示:
1、 在分页虚拟存储系统中,当硬件发出缺页中断时,若内存中已无空闲块,当采用FIFO算法时,则淘汰最先进入内存的页,若该页修改过,还要存入磁盘,然后,再把当前要访问的页装入该块,并修改表中的对应标志.
2、 当采用LRU算法时,则淘汰最近很少访问的页.
两算法均可采用一个数组或链表记录内存中页号的排序,每次将链首页淘汰.数组或链表中只包含页的虚页号─项信息,其它信息通过查页表得到.
<四>实验报告:
(1)、程序中使用数据结构和符号说明.
(2)、给出程序流程.
(3)、打印初始页表、调入/出的页、每执行完一条指令页表的状态及得到的内存地址
(4)、编程语言不限。
页表
package test;
public class Page {
// 页号
private int pageNo;
// 标志 0 表示对应页已转入主存 1 表示对应页为装入主存
private int sign;
// 主存块号 表示该页对应的主存块的块号
private int mainStoreNo;
//外存地址 表示该页所在的外存物理
private String jerryLee;
//修改值
private int changeNum;
public Page() {
}
public Page(int pageNo, int sign, int mainStoreNo, String jerryLee, int changeNum) {
this.pageNo = pageNo;
this.sign = sign;
this.mainStoreNo = mainStoreNo;
this.jerryLee = jerryLee;
this.changeNum = changeNum;
}
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getSign() {
return sign;
}
public void setSign(int sign) {
this.sign = sign;
}
public int getMainStoreNo() {
return mainStoreNo;
}
public void setMainStoreNo(int mainStoreNo) {
this.mainStoreNo = mainStoreNo;
}
public String getJerryLee() {
return jerryLee;
}
public void setJerryLee(String jerryLee) {
this.jerryLee = jerryLee;
}
public int getChangeNum() {
return changeNum;
}
public void setChangeNum(int changeNum) {
this.changeNum = changeNum;
}
@Override
public String toString() {
return "Page{" +
"pageNo=" + pageNo +
", sign=" + sign +
", mainStoreNo=" + mainStoreNo +
", jerryLee=" + jerryLee +
", changeNum=" + changeNum +
'}';
}
}
作业执行的指令序列
package test;
public class Work {
//操作
private String operation;
//页号
private int pageNum;
//单元号
private String unitNum;
public Work(String operation, int pageNum, String unitNum) {
this.operation = operation;
this.pageNum = pageNum;
this.unitNum = unitNum;
}
public Work() {
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public String getUnitNum() {
return unitNum;
}
public void setUnitNum(String unitNum) {
this.unitNum = unitNum;
}
@Override
public String toString() {
return "Work{" +
"operation='" + operation + '\'' +
", pageNum=" + pageNum +
", unitNum='" + unitNum + '\'' +
'}';
}
}
package test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Main {
private static final List<Page> PAGE_TABLE = new ArrayList<>(7);
private static final List<Work> WORK_LIST = new ArrayList<>();
//链表
public static class Node{
public Page data;
public Node next;
public Node(Page data) {
this.data = data;
}
public Node() {
}
}
//初始化头节点
private static final Node NODE_HEADER = new Node(null);
public static Node getHeader(){
return NODE_HEADER;
}
//添加数据
public static void add(Node node){
Node header = getHeader();
while(true){
if(header.next == null){
break;
}
header = header.next;
}
header.next = node;
}
// 链表长度
public static int length(){
Node header = getHeader();
int i = 0;
while (true) {
if(header.next == null){
break;
}
i++;
header = header.next;
}
return i;
}
//插入节点
public static void insert(int index,Page data){
Node header = getHeader();
Node n = new Node();
index = index - 1;
if(header.next == null){
add(new Node(data));
}
n.data = data;
n.next = header.next;
header.next = n;
}
//索取索引位置上的数据
public static Node getNodeByIndex(int index){
Node header = getHeader();
index = index -1;
for(int i = 0;i < length();i++){
if(i != index){
header = header.next;
}
}
return header.next;
}
//移除最后的元素
private static void removeLast(){
Node header = getHeader();
while(true){
if(header.next.next == null){
header.next = null;
break;
}
header = header.next;
}
}
// 打印执行流程
public static void FIFO(){
Node header = getHeader();
System.out.print("页面顺序:");
while(true){
if(header.next == null){
System.out.println();
break;
}
System.out.print(header.next.data.getPageNo() + " ");
header = header.next;
}
}
//模拟硬盘
private static void initPageTable(){
Page page = new Page( 0,1,5,"011",1);
Page page1 = new Page(1,1,8,"012",1);
Page page2 = new Page(2,1,9,"013",0);
Page page3 = new Page(3,1,1,"021",0);
Page page4 = new Page(4,0,0,"022",0);
Page page5 = new Page(5,0,0,"023",0);
Page page6 = new Page(6,0,0,"121",0);
PAGE_TABLE.add(page);
PAGE_TABLE.add(page1);
PAGE_TABLE.add(page2);
PAGE_TABLE.add(page3);
PAGE_TABLE.add(page4);
PAGE_TABLE.add(page5);
PAGE_TABLE.add(page6);
for (Page p : PAGE_TABLE) {
if (p.getSign() == 1) {
Node node = new Node(p);
add(node);
}
}
initWork();
}
private static Page byPage(int pageNo){
Page page1 = new Page();
for (Page page : PAGE_TABLE) {
if(page.getPageNo() == pageNo){
page1 = page;
break;
}
}
return page1;
}
//初始化作业执行的指令序列
private static void initWork(){
Work work = new Work("+",0,"070");
Work work1 = new Work("+",1,"050");
Work work2 = new Work("*",2,"015");
Work work3 = new Work("存",3,"021");
Work work4 = new Work("取",0,"057");
Work work5 = new Work("-",6,"040");
Work work6 = new Work("移位",4,"053");
Work work7 = new Work("+",5,"023");
Work work8 = new Work("存",1,"037");
Work work9 = new Work("取",2,"076");
Work work10 = new Work("+",4,"001");
Work work11 = new Work("取",6,"084");
WORK_LIST.add(work);
WORK_LIST.add(work1);
WORK_LIST.add(work2);
WORK_LIST.add(work3);
WORK_LIST.add(work4);
WORK_LIST.add(work5);
WORK_LIST.add(work6);
WORK_LIST.add(work7);
WORK_LIST.add(work8);
WORK_LIST.add(work9);
WORK_LIST.add(work10);
WORK_LIST.add(work11);
}
// 第二步 执行作业中的页表
private static void executePageTable(){
for (Work work : WORK_LIST) {
Page page = byPage(work.getPageNum());
System.out.println("操作的页:" + work.getPageNum());
if(page.getSign() == 1){
System.out.println("该页存在内存中");
//绝对地址
String absoluteAddress = Integer.toHexString(page.getMainStoreNo() * 128 + Integer.parseInt(work.getUnitNum(), 8));
System.out.println("绝对地址:" + absoluteAddress);
}else if(page.getSign() == 0){
System.out.println( page.getPageNo() + ":该页不在内存中");
System.out.println("产生缺页中断");
//获取外存地址
String jerryLee = page.getJerryLee();
//缺页中断 执行fifo算法
Page page1 = byJerryLeeToPage(jerryLee);
if(page1 == null){
throw new RuntimeException("地址非法");
}
fifoAlgorithm(page1);
}else{
throw new RuntimeException("地址非法");
}
System.out.println("================执行 '"+work.getOperation() +"' 操作===============");
System.out.println("页号\t\t标志\t\t内存块号\t\t外存地址\t\t修改值");
printfPage_Table();
FIFO();
System.out.println("===========================================================");
}
}
private static void printfPage_Table() {
for (Page page : PAGE_TABLE) {
System.out.println(" "+page.getPageNo()+"\t\t "+page.getSign()+"\t\t "+page.getMainStoreNo()+"\t\t "+page.getJerryLee()+"\t\t "+page.getChangeNum());
}
}
private static Page byJerryLeeToPage(String jerryLee) {
for (Page page : PAGE_TABLE) {
if(page.getJerryLee().equals(jerryLee)){
return page;
}
}
return null;
}
// 产生缺页中断后执行的方法
private static void fifoAlgorithm(Page page){
Node nodeByIndex = getNodeByIndex(4);
Page data = nodeByIndex.data;
removeLast();
System.out.println("淘汰的页:" + data.getPageNo());
insert(1,page);
byPage(page.getPageNo()).setSign(1);
byPage(data.getPageNo()).setSign(0);
byPage(page.getPageNo()).setMainStoreNo(data.getMainStoreNo());
byPage(data.getPageNo()).setMainStoreNo(0);
}
public static void main(String[] args) {
initPageTable();
executePageTable();
}
}
具体执行流程