一、实验目的
连续内存分配方式会形成许多“碎片”,虽然可以通过“紧凑”方法将许多碎片拼接成可用的大块空间,但须为之付出很大开销。如果允许将一个进程直接分散地装入到许多不相邻接的分区中,则无需再进行“紧凑”。基于这一思想而产生了离散分配方式。
如果离散分配的基本单位是页,则称为分页存储管理方式;如果离散分配的基本单位是段,则称为分段存储管理方式。
在分页存储管理方式中,如果不具备页面兑换功能,则称为基本的分页存储管理方式,或称为纯分页存储管理方式,它不具备支持虚拟存储器的功能,它要求把每个作业全部装入内存后方能运行。
本实验通过程序模拟操作系统的基本分页存储管理方式,进一步理解这一内存分配方式的原理和特点,加深对理论知识的掌握。
二、实验要求
1、用C语言或Java语言编写程序模拟操作系统对内存的基本分页存储管理方式
2、程序要能正确对“内存”进行“分配”和“回收”,能接受用户的输入,显示内存的分配情况,并有一定的容错能力。
3、每个人独立按时完成实验内容。
三、实验内容
本实验假定内存空间已经按块划分,目标程序无需关心内存块大小等底层细节,只需按算法对内存块进行分配即可。程序应该实现以下功能:
1、内存初始化。假定内存块共有N个,初始化后的内存空间应该有一部分已经被使用,这可以用随机数或程序内部的其他算法完成。
2、程序应该能接受用户输入的进程信息,并为之分配内存,返回分配结果(成功或失败),注意,此处应该考虑到不合法的输入并进行相应处理。
3、程序能回收用户指定的进程所占用的内存空间,因此,程序可能需要为每个进程分配一个唯一的进程号并给出详细的提示信息。
4、能直观合理地显示内存分配情况。
5、程序界面友好,便于操作和查看运行结果。
#include "windows.h" #include <conio.h> #include <stdlib.h> #include <fstream.h> #include <io.h> #include <string.h> #include <stdio.h> #include <iostream.h> void initialize(); void createps(); void displayinfo(); void fifo(); int findpage(); void lru(); int invalidcount = 0; // 缺页次数 int vpoint; //页面访问指针 int pageframe[10]; // 分配的页框 int pagehistory[10]; //用以记录页框中数据访问历史 int rpoint; //页面替换指针 int inpflag; //缺页标志,0为不缺页,1为缺页 //页面信息结构 struct PageInfo { int serial[100]; // 模拟的最大访问页面数,实际控制在20以上 int flag; // 标志位,0表示无页面访问数据 int diseffect; // 缺页次数 int total_pf; // 分配的页框数 int total_pn; // 访问页面序列长度 } pf_info; /////////////////////////////////////////////////////////////////// //初始化相关数据结构 void initialize() { int i,pf; inpflag=0; //缺页标志,默认值为0不缺页 pf_info.diseffect =0; //缺页次数,默认0 pf_info.flag =0; //标志位,0表示无页面访问数据 //cout<<"请输入要分配的页框数:"; //cin>>pf; //cout<<endl; pf_info.total_pf =pf; //自定义输入页框数 for(i=0;i<100;i++) // 清空页面序列 { pf_info.serial[i]=-1; } } //////////////////////////////////////////////////////////////////////// /// 随机生成访问序列 void createps(void ) { int s,i,pn; initialize(); //初始化相关数据结构 // cout<<"请输入要随机产生的访问序列的长度:"; //cin>>pn; //cout<<endl; srand(rand()); //初始化随机数队列的"种子" s=(rand() / 32767) * 50 + pn; // 根据需求产生访问序列长度 pf_info.total_pn = s; for(i=0;i<s;i++) //产生随机访问序列 { pf_info.serial[i]=(rand() / 32767) * 16;//限定随机数大小在16以内 } } //////////////////////////////////////////////////////////////////////// // 显示当前状态及缺页情况 void displayinfo(void) { int i,n; if(vpoint==0) { printf(" =============页面访问序列============= "); for(i=0; i<pf_info.total_pn; i++) { printf("M",pf_info.serial[i]); if ((i+1) % 10 ==0) printf(" ");//每行显示10个 } printf(" ====================================== "); } printf("访问= : 内存<",pf_info.serial[vpoint]); for(n=0;n<pf_info.total_pf;n++) // 页框信息 { if (pageframe[n] >=0) printf("=",pageframe[n]); else printf(" "); } printf(" >"); if(inpflag==1) { printf(" ==>缺页 "); printf("缺页率%3.1f",(float)(pf_info.diseffect)*100.00/vpoint); } printf(" "); } //////////////////////////////////////////////////////////////////////// // 查找页面是否在内存,1为在内存,0为不在即缺页 int findpage(int page) { int n; for(n=0;n<pf_info.total_pf;n++) { pagehistory[n]++;//页面访问历史记录 } for(n=0;n<pf_info.total_pf;n++) { if(pageframe[n]==page) { inpflag=0; pagehistory[0]=0; return 1; } } inpflag=1; //页面不存在,缺页 return 0; } //////////////////////////////////////////////////////////////////////// // FIFO页面置换算法 void fifo(void) { int n,count,pstate; rpoint=0; // 页面替换指针 invalidcount = 0; // 缺页数初始化为0 // 随机生成访问序 count=0; // 是否装满页框 // createps(); // 随机产生访问序列 for(n=0;n<pf_info.total_pf;n++) // 清除页框信息 pageframe[n]=-1; inpflag=0; for(vpoint=0;vpoint<pf_info.total_pn;vpoint++) // 执行算法 { pstate=findpage(pf_info.serial[vpoint]); if(count<pf_info.total_pf) // 开始时不计算缺页 { if(pstate==0)// 页不存在则装入页面 { pageframe[rpoint]=pf_info.serial[vpoint]; rpoint=(rpoint+1) % pf_info.total_pf; count++; } } else // 正常缺页置换 { if(pstate==0)// 页不存在则置换页面 { pageframe[rpoint]=pf_info.serial[vpoint]; rpoint=(rpoint+1) % pf_info.total_pf; pf_info.diseffect=pf_info.diseffect+1; // 缺页次数加1 } } Sleep(1000); displayinfo(); // 显示当前状态 } // 置换算法循环结束 _getch(); return; } /////////////////////////////////////////////////////////////////// //LRU页面置换算法 void lru(void) { int n,count,pstate,max; rpoint =0; invalidcount=0; count =0; // createps(); for(n=0;n<pf_info.total_pf;n++) { pageframe[n]=1; pagehistory[n]=0; } inpflag = 0; for(vpoint=0;vpoint<pf_info.total_pn;vpoint++) { pstate=findpage(pf_info.serial[vpoint]); if(count<pf_info.total_pf) { if(pstate==0) { pageframe[rpoint]=pf_info.serial[vpoint]; rpoint=(rpoint+1)%pf_info.total_pf; count++; } } else { if(pstate==0) { max=0; for(n=1;n<pf_info.total_pf;n++) { if(pagehistory[n]>pagehistory[max]) { max = n; } } rpoint=max; pageframe[rpoint]=pf_info.serial[vpoint]; pagehistory[rpoint]=0; pf_info.diseffect++; } } Sleep(1000); displayinfo(); } _getch(); return; } /////////////////////////////////////////////////////////////////// //主函数 int main(int argc, char* argv[]) { char ch; system("cls") ; //while ( true ) //{ printf("*********************************** "); printf(" 1: FIFO页面置算法 ") ; printf(" 2: LRU页面置算法 ") ; printf(" 3: 生成访问序列 ") ; printf(" 4: 退出 ") ; printf("*********************************** "); printf( "也测试算法,必须先选3 Enter your choice (1or2or3or4): "); do { ch = (char)_getch() ; } while(ch != '1' && ch != '2'&& ch != '3'&& ch != '4'); if(ch == '4') return 0; else { //cout<<endl; if(ch=='1') { system("cls") ; fifo(); } if(ch=='2') { system("cls") ; lru(); } if(ch=='3') { createps(); } if(vpoint==0) { int i,n; printf(" =============页面访问序列============= "); for(i=0; i<pf_info.total_pn; i++) { printf("M",pf_info.serial[i]); if ((i+1) % 10 ==0) printf(" ");//每行显示10个 } printf(" ====================================== "); } } printf(" Press Any Key To Continue:"); _getch() ; return 0; }