目录
一、实验目的
1、掌握基本分页存储管理方式
2、加深对页面、页表等概念的认识和理解
3、通过编写基本分页存储管理模拟程序,理解从算法设计到实现的思想与方法
二、实验要求
分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片称为页面或页,并为各页加以编号,从0开始。同时把内存空间分成与页面相同大小的若干个存储块,称为块或页框。在为进程分配内存时,以块为单位将进程的若干个页分别装入到多个可以不相邻的物理块中。进程的最后一页经常装不满而形成“页内碎片”。
三、实验步骤
分页实现步骤:
1.选取合适的页面大小对内存分页,初态内存修改分区使用说明表;
2.设置多个进程(包含申请的内存大小信息),将每个进程根据页面大小分成若干页,进程每N页依次申请空间,然后在内存状态表中查找,看是否可以将该进程的这N个页面放入内存,如果可以则将该进程放入内存,并修改其页表信息和分区使用说明表;
3. 根据进程的退出次序,再将空间依次进行回收,修改该进程的页表和内存状态表;
4. 要求当每次修改页表和内存状态表时,都要打印一次页表和内存状态表信息。
四、核心代码
//建立新作业
void Create_Pagi(List &L)
{
int i, flag;
int m, k;
List p;
List n_node;
n_node = (List)malloc(sizeof(Ln));
p = L;
printf(" 亲,请输入作业号 :");
scanf("%d", &n_node->f); //输入作业号
flag = 0; //三次输入错误返回上一层
while (p != NULL && flag < 3) // 查找作业号是否重复
{
if (p->f != n_node->f)
p = p->next;
else
{
printf("\n 亲,该作业已存在您忘记了吗 , 请重新输入 :");
scanf("%d", &n_node->f);
p = L; //p 重新指向头结点
flag++;
}
}
if (flag < 3)
{
printf(" 输入作业名称 :");
scanf("%s", n_node->name);
printf(" 输入作业的大小 (单位为K):");
scanf("%d", &n_node->len);
n_node->n = n_node->len / 1024;
k = n_node->len % 1024;
if (k != 0)
n_node->n = n_node->n + 1;
printf(" 所需要的页数为 :");
printf("%d\n", n_node->n);
printf(" 偏移量为%d", k);
if (n_node->n > num) //放不进去,失败
{
printf("\n 对不起亲,内存物理块不足,新建作业失败 \n\n");
}
else
{
num -= n_node->n; //更新剩余物理块
m = 0;
for (i = 0; i <= max; i++)
if (S[i] == 0 && m < n_node->n) //
{
S[i] = n_node->f; //作业号
n_node->y[m] = i; //页表,下标表示页号,内容表示作业各页所在物理块
m++;
}
printf("\n");
printf(" 页号\t\t块号\n");
for (int i = 0; i < m; i++)
printf(" %d\t\t%d\n", i, n_node->y[i]);
int a, b;
while (1)
{
printf(" 请输入页号\n");
scanf("%d", &a);
printf(" 请输入页内偏移\n");
scanf("%d", &b);
if (a < m)
{
printf(" 物理地址:%d\n", n_node->y[a] * 1024 + b);
break;
}
else
{
printf(" 越界\n");
continue;
}
}
if (L == NULL)
L = n_node;
else
{
p = L; // 查找最后一个节点
while (p->next != NULL)
{
p = p->next;
}
p->next = n_node;
}
n_node->next = NULL;
}
}
else
{
printf("\n 亲操作错误次数过多 , 已为您返回主菜单 :");
}
}
//回收作业、释放内存
void Revoke_Pagi(List &L)
{
List p, q;
int x;
printf(" 请输入要删除的作业号 :");
scanf("%d", &x);
p = L; //查找作业;用 p 记录
q = p;
while (p != NULL)
{
if (p->f == x) //作业号
{
printf(" 该作业已删除成功 ");
break;
}
else
{
q = p;
p = p->next;
}
}
if (p == NULL) //p为空说明不存在此作业
{
printf("\n 该作业不存在!\n");
}
else //对该作业进行删除
{
for (int i = 0; i < p->n; i++)
S[p->y[i]] = 0; //内存物理块
num += p->n;
if (p->f == q->f) //要删除的是头结点
{
L = p->next;
}
else
{
q->next = p->next;
}
}
}
// 显示所有作业占用的物理块
void Printf_Pagi(List L)
{
printf("\n 内存物理块分配情况 :\n");
List p = L;
printf(" 该作业信息 :\n");
printf(" 作业号 \t 作业名称 \t 作业页数 \t 所用物理块 \n");
while (p != NULL)
{
printf(" %d\t\t", p->f);
printf(" %s\t\t", p->name);
printf(" %d\t\t", p->n);
int i;
for (i = 0; i < p->n; i++)
printf(" %d", p->y[i]);
printf("\n");
p = p->next;
}
}
// 查看作业
void Look_Pagi(List L)
{
int z;
printf(" 请输入要查询的作业号: ");
scanf("%d", &z); //输入查看的作业号
List p = L;
while (p != NULL)
{
if (p->f == z) //相同直接输出
{
printf(" 作业号 \t 作业名称 \t 作业页数 \t 所用物理块 \n");
printf(" %d\t\t", p->f);
printf(" %s\t\t", p->name);
printf(" %d\t\t", p->n);
int i;
for (i = 0; i < p->n; i++)
printf(" #%d", p->y[i]);
printf("\n");
break;
}
else
p = p->next;
}
if (p == NULL)
printf(" 要查询的作业不存在! \n");
}
// 显示内存块使用情况,不分作业
void Show_Pagi()
{
printf(" 内存物理块分配情况 \n");
for (int i = 0; i <= max; i++)
{
printf(" %d\t", S[i]);
if (i % 10 == 9)
printf("\n");
}
}
//分页
void Pagi()
{
memset(S, 0, sizeof(S)); //初始化A
List L = NULL;
int i = 0;
do
{
printf("\t\t 欢迎使用基本分页存储管理系统 \n");
printf("\t\t******************************\n");
printf("\t\t* 1. 添加作业 *\n");
printf("\t\t* 2. 回收作业 *\n");
printf("\t\t* 3. 内存占用情况 *\n");
printf("\t\t* 4. 查看作业 *\n");
printf("\t\t* 5. 提出宝贵建议 *\n");
printf("\t\t* 6. 返回主界面 *\n");
printf("\t\t* 0. 退出程序 *\n");
printf("\t\t******************************\n");
printf(" 请输入您的选择 :");
scanf("%d", &i);
switch (i)
{
case 1:
Create_Pagi(L);
break;
case 2:
Revoke_Pagi(L);
Printf_Pagi(L);
break;
case 3:
Show_Pagi();
break;
case 4:
Look_Pagi(L);
break;
case 5:
main_s();
break;
case 0:
printf(" 感谢您的使用,祝您生活愉快!");
exit(0);
}
} while (i != 0);
}
void main_s()
{
printf("\t\t 欢迎来到内存管理系统 \n");
printf("\t\t**********************\n");
printf("\t\t* 1.进入分页管理系统 *\n");
printf("\t\t* 0.退出程序 *\n");
int m;
printf(" 亲,请输入您的选择 :");
scanf("%d", &m);
do
if (m >= 0 && m <= 3)
{
switch (m)
{
case 1:
Pagi(); //分页
break;
case 0:
exit(0);
}
}
else
{
printf(" 输入有误!请重新输入:");
scanf("%d", &m);
}
while (m != 0);
}
五、记录与处理
六、思考
1. 基本分页存储管理思想:把内存分为一个个相等的小分区,再按照分区大小把进程拆分成一个个小部分。
2. 实验中涉及到了连续分配与非连续分配的概念,连续分配:为用户进程分配的必须是一个连续的内存空间;非连续分配:为用户进程分配的可以是一些分散的内存空间。
连续分配的缺点:固定分区分配:缺乏灵活性,产生大量内部碎片,内存利用率很低。动态分区分配:产生很多外部碎片,可以用‘紧凑’技术处理,但代价很高。连续分配:为用户进程分配的必须是一个连续的内存空间。非连续分配:为用户分配的是一些分散的内存空间。
3. 操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。进程的最后一个页面可能没有一个页框那么大。即,分页存储有可能产生内部碎片,因此页框不能太大,否则可能产生过大的内部碎片造成浪费。
4.通过此实验我深入了解了分页存储管理的概念及其在实际系统中的应用,本次实验不仅增强了我对操作系统中内存管理机制的认识,也让我体验了从算法设计到实际编程实现的完整过程。
七、完整报告和成果文件提取链接
链接:https://pan.baidu.com/s/1UbP6729pCluscVW0_9oI8w?pwd=1xki
提取码:1xki