三种存储管理方式的地址换算摘要:操作系统(Operating System,OS)是方便用户、管理和控制计算机软硬件资源的系统软件(或程序集合)。
从用户角度看,操作系统可以看成是对计算机硬件的扩充;从人机交互方式来看,操作系统是用户与机器的接口;从计算机的系统结构看,操作系统是一种层次、模块结构的程序集合,属于有序分层法,是无序模块的有序层次调用。
操作系统在设计方面体现了计算机技术和管理技术的结合。
操作系统是系统软件的核心,、它控制程序的执行和提供资源分配、调度、输入/输出控制和数据管理等任务。
如DOS、UNIX、OS/2和Windows NT都是得到广泛使用的操作的系统。
三种管理方式中,分页系统能有效地提高内存利用率,分段系统则能很好地满足用户需要,而段页式系统则是把前两种结合起来形成的系统。
这种新系统既具有分段系统的便于实现、分段可共享、易于保护、可动态链接等一系列优点,有能像分页系统那样很好地解决内存的外部碎片问题,以及可为各个分段离散地分配内存等问题。
关键字:分页方式,分段方式,段页式方式,操作系统。
1.引言:分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片,称为页面或页。
在分段存储管理方式中,作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。
段的长度由相应的逻辑信息组的长度决定,因而个段长度不等。
段页式存储管理方式是分段和分页原理的结合,即先将用户程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。
三种存储管理都有其相应的段表、页表和地址变换机构。
2.三种存储管理方式地址换算描述:(1)分页存储管理方式为了实现从进程的逻辑地址到物理地址的变换功能,在系统中设置了页表寄存器,用于存放页表在内存中的始址和页表的长度。
当进程要访问某个逻辑地址中的数据时,分页地址变换机构会自动地将有效地址(相对地址)分为页号和页内地址两部分,再以页号为索引去检索页表。
查找操作由硬件执行。
在执行检索之前,先将页号与页表长度进行比较,如果页号大于或等于页表长度,则表示本次所访问的地址已超越进程的地址空间。
于是,这一错误将被系统发现并产生一地址越界中断。
若未出现越界错误,则将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,于是可从中得到该页的物理块号,将之装入物理地址寄存器中。
与此同时,再将有效地址寄存器中的页内地址送入物理地址寄存器的块内地址字段中。
这样便完成了从逻辑地址到物理地址的变换。
(2)分段存储管理方式为了实现从进程的逻辑地址到物理地址的变换功能,在系统中设置了段表寄存器,用于存放段表始址和段表长度TL。
在进行地址变换时,系统将逻辑地址中的段号与段表长度TL进行比较。
若S>TL,表示段号太大,是访问越界,于是产生越界中断信号;若未越界,则根据段表的始址和该段的段号,计算出该段对应段表项的位置,从中读出该段在内存的起始地址,然后,再检查段内地址d是否超过该段的段长SL。
若超过,即d>SL,同样发出越界中断信号;若未越界,则将该段的基址与段内地址d相加,即可得到要访问的内存物理地址。
(3)段页存储管理方式在段页式系统中,为了便于实现地址变换,需配置一个段表寄存器,其中存放段表始址和段表长TL。
进行地址变换时,首先利用段号S,将它与段表长TL 进行比较。
若S>TL,表示未越界,于是利用段表始址和段号来球出该段所对应的段表项在段表中的位置,从中得到该段的页表始址,并利用逻辑地址中的段内页号P来获得对应表的页表项位置,从中读出该页所在的物理块号b,再利用块号b和页内地址来构成物理地址。
3.程序模块:#include <stdlib.h>#include <stdio.h>int settable1(int n,int k);//创建页表int printTable1(int n,int k);//显示页表int transt(int n,int k,int add);//分页地址换算int defSect(int n,int *t);//创建段表int printSect(int n);//输出段表内容int transSect(int n,int s,int d);//进行分段地址换算函数int setSectTable(int n,int k);//创建段页式内容int printSectTable(int n,int k);//显示段页内容int transSectPage(int n,int k,int s1,int s2,int s3);//段页式地址换算//定义页表结构体typedef struct stable{int y1;//页号int y2;//块号}stable;struct stable setst[512];//建立段表的结构体typedef struct setsect{int d1;//段号int d2;//段长int d3;//基址}setsect;struct setsect sets[512];//定义段表的总长度//建立段页式内的页表的结构体typedef struct table{int dy1;//页号int dy2;//块号}table;//建立段页式的结构体typedef struct setAll{struct table c1[512];//定义段内页表的结构体int c2;//段号int c3;//段长int c4;//起始地址}setAll;struct setAll set[512];//定义段页式的总长度4.三种存储管理方式的地址变换机构(1)分页系统的地址变换机构实用文档(2) 分段系统的地址变换机构(3) 段页式系统中的地址变换机构5.结束语:为期二周的操作系统课程设计很快就结束了,做为每个学期末的一项必修课,课程设计的目的就是要让我们能够更加深刻的理解课堂上所学的知识,并能够将它们应用到实践中去,让知识能为实践服务。
这次操作系统的课程设计,我是通过编程演示三种存储管理方式的地址换算过程。
通过这次课程设计,加深了我对课堂上所学的三种存储管理方式的地址换算的概念的理解,了解了操作系统的工作原理已经平时遇到的一些状况是怎么样产生的,通过这次操作系统的课程设计,另我学到了很多在课堂上学不到的知识,以及动手能力,这次课程设计老师不限开发工具,因此也锻炼了我们对新的开发工具的掌握能力。
对于我们计算机专业的学生来说,在软件更新如此之快的今天,对新的开发工具的快速掌握能力也是一项必不可少的能力。
当然,在这次课程设计中,也暴露出来了一些问题,就是我对开发工具的使用,虽然大学三年基本是用C编写程序比较多,但是还是感到了力不从心的感觉,就是自己对一些C函数库的了解不够,导致自己在用的时候走了很多弯路,这也从间接让我了解了许多平时学习不到的知识。
课程设计不仅能锻炼我们把知识应用于实践的能力,还锻炼了我们思维的逻辑性。
编写一个BUG尽可能少的程序,需要考虑很多方面的问题,包括给别人试用,这就锻炼了我们逻辑思维的能力,为今后走上工作岗位打下了坚实的基础。
6.参考文献:《计算机操作系统》西安电子科技大学出版社《C语言程序设计教程》机械工业出版社附:三种存储管理方式地址换算程序清单如下:#include <stdlib.h>#include <stdio.h>int settable1(int n,int k);//创建页表int printTable1(int n,int k);//显示页表int transt(int n,int k,int add);//分页地址换算int defSect(int n,int *t);//创建段表int printSect(int n);//输出段表内容int transSect(int n,int s,int d);//进行分段地址换算函数int setSectTable(int n,int k);//创建段页式内容int printSectTable(int n,int k);//显示段页内容int transSectPage(int n,int k,int s1,int s2,int s3);//段页式地址换算//定义页表结构体typedef struct stable{int y1;//页号int y2;//块号}stable;struct stable setst[512];//建立段表的结构体typedef struct setsect{int d1;//段号int d2;//段长int d3;//基址}setsect;struct setsect sets[512];//定义段表的总长度//建立段页式内的页表的结构体typedef struct table{int dy1;//页号int dy2;//块号}table;//建立段页式的结构体typedef struct setAll{struct table c1[512];//定义段内页表的结构体int c2;//段号int c3;//段长int c4;//起始地址}setAll;struct setAll set[512];//定义段页式的总长度int main(){int choice1,choice2;int truth=0,truth1;int jobAddr;//进程的逻辑地址空间int md;//页面大小int addr1;//输入的逻辑地址int dc;//定义段表的长度int dh,sAddr;//定义段表的逻辑地址的段号和段内地址int dyc;//段页式的段表长度int jobs,jobt,joba;//段页式逻辑段号、段内页号、页内地址do{printf(" 组员:符小平崔健王菲菲王天渤\n");printf("--------------操作系统课程设计题目:分页、分段、段页式地址换算-------------------\n\n");printf(" 总菜单\n");printf(" 1.分页方式\n");printf(" 2.分段方式\n");printf(" 3.段页式\n");printf(" 4.结束\n\n");printf("----------------------------------------------------------\n"); printf("请输入您的选择:\n");scanf("%d",&choice1);switch(choice1){case 1:{//分页方式do{printf(" 分页方式\n");printf("---------------------------------------------------\n");printf(" 1.随机生成进程大小\n");printf(" 2.进程创建页表\n");printf(" 3.显示页表的信息\n");printf(" 4.地址换算\n");printf(" 5.退出\n");printf("---------------------------------------------------\n\n"); printf("请输入您的选择:");scanf("%d",&choice2);switch(choice2){case 1:{printf(" 随机生成一个进程(大小在1024K至2048K)\n"); printf("---------------------------------------------------\n");do{jobAddr=rand()%2048;//随机产生进程的逻辑地址空间}while(jobAddr<1024);printf("该进程的逻辑地址空间是:%d(K)\n",jobAddr);printf("页面的大小:");scanf("%d",&md);truth=1;printf("---------------------------------------------------\n"); }break;case 2:{if(truth==1){printf("\n 进程创建的页表\n");printf("---------------------------------\n\n"); settable1(jobAddr,md);truth1=1;printf("\n\n---------------------------------\n");}else{printf("\n\n---------------------------------\n"); printf("\n还没有创建进程.请先选择1创建进程.\n\n"); printf("\n\n---------------------------------\n"); break;}}break;case 3:{if(truth==1){if(truth1==1){printf("\n 显示进程创建的页表\n");printf("---------------------------------\n\n"); printTable1(jobAddr,md);printf("\n\n---------------------------------\n");}else{printf("\n\n---------------------------------\n");printf("\n还没有创建页表.请先选择2创建页表.\n\n");printf("\n\n---------------------------------\n");break;}}else{printf("\n\n---------------------------------\n");printf("\n还没有创建进程.请先选择1创建进程.\n\n");printf("\n\n---------------------------------\n");break;}}break;case 4:{if(truth==1){if(truth1==1){printf("\n 地址换算\n");printf("---------------------------------\n\n");printf("请你输入要进行换算的逻辑地址(K):");scanf("%d",&addr1);if(addr1>jobAddr){do{printf("输入的逻辑地址大于进程地址空间,请重新输入逻辑地址(K):"); scanf("%d",&addr1);}while(addr1>jobAddr);}transt(jobAddr,md,addr1);printf("\n\n---------------------------------\n");}else{printf("\n\n---------------------------------\n");printf("\n还没有创建页表.请先选择2创建页表.\n\n");printf("\n\n---------------------------------\n");break;}}else{printf("\n\n---------------------------------\n");printf("\n还没有创建进程.请先选择1创建进程.\n\n");printf("\n\n---------------------------------\n");break;}}break;case 5:{printf("---------------------------------------------------\n\n"); printf("退出分页方式地址换算选项,进入总菜单.\n");printf("---------------------------------------------------\n\n");}break;default:{printf("---------------------------------------\n");printf("错误提示:你输入的选择有错,请重新选择!\n");printf("---------------------------------------\n");}}}while (choice2!=5);}break;case 2:{//分段方式do{printf(" 分段方式地址换算\n");printf("---------------------------------------------------\n"); printf(" 1.创建段表\n");printf(" 2.显示段表\n");printf(" 3.地址换算\n");printf(" 4.退出\n");printf("---------------------------------------------------\n\n"); printf("请输入您的选择:");scanf("%d",&choice2);switch(choice2){case 1:{printf(" 开始创建段表\n");printf("---------------------------------------------------\n"); printf("请输入你要创建的段表长度(最大为512个):");scanf("%d",&dc);defSect(dc,&truth);printf("---------------------------------------------------\n"); }break;case 2:{if(truth==1){printf("\n 显示已经创建的段表内容\n");printf("---------------------------------\n\n");printSect(dc);printf("\n\n---------------------------------\n");}else{printf("\n\n---------------------------------\n");printf("\n还没有创建段表.请先选择1创建段表.\n\n"); printf("\n\n---------------------------------\n");break;}}break;case 3:{if(truth==1){printf(" 分段地址换算\n");printf("---------------------------------------------------\n"); printf("请您输入逻辑地址的段号,段内地址(K):");scanf("%d,%d",&dh,&sAddr);transSect(dc,dh,sAddr);printf("---------------------------------------------------\n"); }else{printf("---------------------------------------------------\n"); printf("\n还没有创建段表.请先选择1创建段表.\n\n");printf("---------------------------------------------------\n"); break;}}break;case 4:{printf("---------------------------------------------------\n\n"); printf("退出分段方式地址换算选项,进入总菜单.\n");printf("---------------------------------------------------\n\n"); }break;default:{printf("---------------------------------------\n");printf("错误提示:你输入的选择有错,请重新选择!\n");printf("---------------------------------------\n");}}}while (choice2!=4);}break;case 3:{//段页式do{printf(" 段页式地址换算\n");printf("---------------------------------------------------\n"); printf(" 1.创建段页式\n");printf(" 2.显示段页式结构\n");printf(" 3.地址换算\n");printf(" 4.退出\n");printf("---------------------------------------------------\n\n"); printf("请输入您的选择:");scanf("%d",&choice2);switch(choice2){case 1:{printf(" 开始创建段页式\n");printf("---------------------------------------------------\n"); printf("请输入你要创建的段表长度(最大为512个):");scanf("%d",&dyc);printf("页面的大小K:");scanf("%d",&md);setSectTable(dyc,md);truth=1;printf("---------------------------------------------------\n"); }break;case 2:{if(truth==1){printf("\n 显示段页式结构\n");printf("---------------------------------\n\n"); printSectTable(dyc,md);printf("\n\n---------------------------------\n");}else{printf("\n\n---------------------------------\n");printf("\n还没有创建段页式.请先选择1创建段页式.\n\n"); printf("\n\n---------------------------------\n");break;}}break;case 3:{if(truth==1){printf(" 段页式地址换算\n");printf("---------------------------------------------------\n"); printf("请输入要查找的逻辑地址段号:");scanf("%d",&jobs);printf("段内页号:");scanf("%d",&jobt);printf("页内地址(K):");scanf("%d",&joba);transSectPage(dyc,md,jobs,jobt,joba);printf("---------------------------------------------------\n"); }else{printf("---------------------------------------------------\n"); printf("\n还没有创建段表.请先选择1创建段页式.\n\n"); printf("---------------------------------------------------\n"); break;}}break;case 4:{printf("---------------------------------------------------\n\n");printf("退出段页式地址换算选项,进入总菜单.\n");printf("---------------------------------------------------\n\n"); }break;default:{printf("---------------------------------------\n");printf("错误提示:你输入的选择有错,请重新选择!\n");printf("---------------------------------------\n");}}}while (choice2!=4);}break;case 4:{printf("准备退出程序!!!\n");}break;default:{printf("---------------------------------------\n");printf("错误提示:你输入的选择有错,请重新选择!\n");printf("---------------------------------------\n");}}}while (choice1!=4);return (0);}//创建页表int settable1(int n,int k){int p;//页号int d;//剩余地址int i;int block;//块号p=n/k;//求出逻辑地址空间总页数d=n%k;//求出该页大小block=1024*1024/k; //求出最大块号for(i=0;i<p;i++){setst[i].y1=i;//页号setst[i].y2=rand()%block;//定义随机产生的块号在1到(1M内存/页面大小)}printf("正在创建中··\n");if(d!=0){setst[p].y1=p;//页号setst[p].y2=rand()%block;//定义随机产生的块号在1到(1M内存/页面大小)之间}printf("\n页表已经创建成功!");return (0);}//显示页表int printTable1(int n,int k){int p;int d;p=n/k;//求出总页数d=n%k;//求出该页大小printf(" 进程逻辑地址空间:%dK 页面大小:%dK\n",n,k); printf(" 页表\n");if(d!=0){for(i=0;i<=p;i++){printf("页号:%d->块号:%d\n",setst[i].y1,setst[i].y2); }}else{for(i=0;i<p;i++){printf("页号:%d->块号:%d\n",setst[i].y1,setst[i].y2); }}return (0);}//分页地址换算int transt(int n,int k,int add){int p1,d1;p1=add/k;//求出逻辑页号d1=add%k;//求出逻辑页内地址printf("\n 分页地址换算结果.\n");printf("---------------------------------\n");printf("进程逻辑地址空间=%dK\n",n);printf("页面大小=%dK\n",k);printf("给定的逻辑地址=%dK\n",add);printf("页号=%d\n",p1);printf("块号=%d\n",setst[p1].y2);printf("起始地址=%dK\n",setst[p1].y2*k);printf("页内地址=%dK\n",d1);printf("物理地址=(起始地址+页内地址)=%dK\n",setst[p1].y2*k+d1); printf("\n---------------------------------\n");return (0);}//创建段表int defSect(int n,int *t){int i;printf("\n 开始给各个段号分配段长和基址.\n");printf("-------------------------------------------\n");for(i=0;i<n;i++){sets[i].d1=i;printf("定义第%d段的段长(K):",i);scanf("%d",&sets[i].d2);//自己定义段长(10~50)sets[i].d3=rand()%2048;//定义随机产生基址为1到2048之间}*t=1;printf("\n---------------------------------\n");return (0);}//输出段表int printSect(int n){int i;printf(" 段表\n");for(i=0;i<n;i++){printf("\n");printf("段号:%d->段长:%dK->起始地址:%dK",sets[i].d1,sets[i].d2,sets[i].d3);}return (0);}//进行分段地址换算int transSect(int n,int s,int d){int sum;printf(" 分段地址换算结果");printf("\n-----------------------------------\n");if(s<n){//段号与段表长度比较if(d<=sets[s].d2){//段内地址与该段的段长比较sum=sets[s].d3+d;printf("查找段号=%d\n",s);printf("该段段长=%dK\n",sets[s].d2);printf("该段起始地址=%dK\n",sets[s].d3);printf("分段地址中的段内地址=%dK\n",d);printf("物理地址=(起始地址+段内地址)=%dK\n",sum);}else{printf("输入的段内地址超过该段的段长,访问越界,产生越界中断信号!\n");}}else{printf("输入的段号太大,访问越界,产生越界中断信号\n!");}printf("-----------------------------------\n\n");return (0);}//创建段页式内容int setSectTable(int n,int k)int p,d;int i,j;int block;block=1024*1024*1024/k;//求出最大块号for(i=0;i<n;i++){set[i].c2=i;printf("定义第%d段的段长(大于1024K,小于2048K):",i);scanf("%d",&set[i].c3);//自己定义段长p=set[i].c3/k;d=set[i].c3%k;set[i].c4=rand()%1024;//定义随机产生的起始地址在1到1024之间for(j=0;j<p;j++){set[i].c1[j].dy1=j;//页号set[i].c1[j].dy2=rand()%block;//定义随机产生的起始地址在1到(1G内存/页面大小)之间}if(d!=0){set[i].c1[p].dy1=p;//页号set[i].c1[p].dy2=rand()%block;//定义随机产生的起始地址在1到(1G内存/页面大小)之间}return (0);}//显示段页式内容int printSectTable(int n,int k){int i,j;int s,p,d;printf(" 段表长度:%d 页面大小:%dK\n",n,k);printf(" 段页式:");for(i=0;i<n;i++){printf("\n段号:%d->页表大小:%dK->页表起始地址:%dK-->页表\n",i,set[i].c3,set[i].c4);s=set[i].c3;p=s/k;d=s%k;//显示段页式结构的内容if(d!=0){for(j=0;j<=p;j++){printf("页号:%d->块号:%d\n",set[i].c1[j].dy1,set[i].c1[j].dy2); }}else{for(j=0;j<p;j++){printf("页号:%d->块号:%d\n",set[i].c1[j].dy1,set[i].c1[j].dy2); }}}return (0);}//段页式地址换算int transSectPage(int n,int k,int s1,int s2,int s3){int p,d,s;printf("\n 段页式地址换算结果.\n");printf("-----------------------------------------\n");if(s1<n){s=set[s1].c3;p=s/k;//求出逻辑地址所在的页号d=s%k;//求出逻辑地址的页内地址if(d!=0){if(s2<=p){printf("段长=%d\n",n);printf("段号=%d\n",s1);printf("段号为%d的始址=%dK\n",s1,set[s1].c4);printf("页面大小=%dK\n",k);printf("段号为%d的页表总页数=%d\n",s1,p+1);printf("段内页号=%d\n",s2);printf("块号=%d\n",set[s1].c1[s2].dy2);printf("页号为%d始址=(块号*页面大小)=%dK\n",s2,set[s1].c1[s2].dy2*k); printf("页内地址=%dK\n",s3);printf("物理地址=(段号始址+页号始址+页内地址)=%dK\n",set[s1].c1[s2].dy2*k+s3);}else{printf("输入的页号大于该段的段内页号,产生越界中断!\n");}}elseif(s2<p){printf("段长=%d\n",n);printf("段号=%d\n",s1);printf("段号为%d的始址=%dK\n",s1,set[s1].c4);printf("页面大小=%dK\n",k);printf("段号为%d的页表总页数=%d\n",s1,p);printf("页号(段内页号)=%d\n",s2);printf("块号=%d\n",set[s1].c1[s2].dy2);printf("页号为%d始址=(块号*页面大小)=%dK\n",s2,set[s1].c1[s2].dy2*k); printf("页内地址=%dK\n",s3);printf("物理地址=(段号始址+页号始址+页内地址)=%dK\n",set[s1].c1[s2].dy2*k+s3);}else{printf("输入的页号大于该段的段内页号,产生越界中断!\n"); }}else{printf("输入段号大于段长,产生越界中断!\n");}printf("-----------------------------------------\n"); return (0);}。