实验三 存储管理
任务二
一、实验名称
存储管理之设计实验
二、实验目的
编写和调试内存管理调度模拟程序,掌握存储管理算法,理解存储管理中地址转换过程。
三、实验过程
1、设计一个固定式分区分配的存储管理方案,并模拟实现分区的分配和回收过程。
假定每个作业都是批处理作业,且不允许动态申请内存。为实现分区的分配和回收,可设定一个分区表,按照表中的有关信息进行分配,并根据分区的分配和回收情况修改该表。
要求∶
1)描述模型、定义数据结构。
①模型:预先将内存空间固定地划分为若干个空闲分区,这样每个分区的大小就确定了,分配内存时作业大小将某一个满足条件的分区直接分配,整个分配和回收过程分区的大小和个数不改变s。
②数据结构
已分配区表
struct
{
float address; //起始地址
float length; //长度
int flag; //登记栏标志
} used_table[n];
空闲区表
struct
{
float address; //起始地址
float length; //长度
int flag; //登记栏标志
} free_table[m];
2)写代码实现并运行调试。
3)给出运行的数据和结果 。
见下图:
初始设置:
分配内存:
回收内存并为新的作业分配内存:
2、设计一个可变式分区分配的存储管理方案并定义数据结构、写代码运行并调试。
要求∶
1)模拟实现分区的分配和回收过程 。
2)分区的管理算法可选择∶首次适应算法、循环首次适应算法和最佳适应算法三种之一,或者自行定义。
这里我采用的是首次适应算法。
首先所谓可变式分区分配是指根据作业的实际需要,动态地为之分配内存。
而首次适应算法,要求空闲分区链以地址递增的次序链接,在分配内存时,从链首开始顺序查找,直到找到一个大小能满足要求的空闲分区为止,然后再按照作业的大小,从该分区中划出一块内存空间分给请求者,余下的空闲分区仍停留在空闲链中。
当回收内存时,系统根据回收区的首址,从空闲区链表中找到相应的插入点,这时若
回收区与插入点的前一个空闲分区F1相邻接,则将两个分区合并;若回收区与插入点的后一个空闲分区F2相邻接,则将两个分区合并;若回收区与插入点的前,后两个空闲分区相邻接,则将三个分区合并;若回收区既不与F1相邻接,又不与F2相邻接,则应为回收区单独建立一个新表项。
为多个作业申请内存:
回收并分配新的内存:
3、设计并调试一个段页式存储管理的地址转换的模拟程序。
要求∶
1)设计段表、页表。
段表
for(i=0; i < n; i++)
{
parag[i].length=i+4;
parag[i].state=1;
parag[i].PTID=d;
d+=parag[i].length;
}
页表
for(i = 0; i < d; i++)
{
page[i].state=1;
page[i].MMID=(i+7)%d;
}
}
结果如下图:
变换过程如下:
①根据段号为2和段内页号为 3,查询段表和页表信息,得到物理块号 19 ;
②由物理块号 19 和块内偏移 428 ,计算19*1024+428=19884即得物理地址 31148 。
四、实验总结
1、对固定分区和可变分区的理解与辨析
固定分区是将内存划分为一块块固定大小的分区,顺序查找可以放下作业的分区,一旦被某个作业占用,即使该分区还有空闲区域也不能使用。
2、…
五、代码
1、固定式分区分配的存储管理
#include<stdio.h>
#include<stdlib.h>
void Allocate(int id, int size);
void Release(int id);
void insert();//输入
void del();
void run();
void start();
void display();
void table();
struct ProcessInfo{
int id;
int size;
};
struct PartitionInfo{
int id;
int size;
int beginAddress;
char status;
};
struct ProcessInfo process[5];
struct PartitionInfo partition[5];
int a[5][2];
void Allocate(int id, int size){
int i;
int j;
for(i=0;i<5; i++){
if(partition[i].status=='T'){
if(partition[i].size>=size){
partition[i].status='F';
for(j=0;j<5;j++){
if(a[j][0]==0){//更新分区表
a[j][0]=id;
a[j][1]= partition[i].id;
printf("插入成功!!\n");
return;
}
}
}
}
}
printf("分配失败!!! 没有可用的内存分区!!!\n");
return ;
}
void Release(int id){
int i;
int j;
for(i=0;i<5;i++){
if(a[i][0]==id)
{
for(j=0;j<5;j++)
{
if(a[i][1]==partition[j].id){
partition[j].status='T';
}
}
for(j=i ;j<5-1;j++){
a[j][0]=a[j+1][0];
a[j][1]=a[j+1][1];
}
}
}
}
void insert(){
int id;
int size;
int i;
printf("请输入进程号:");
scanf("%d",&id);
for(i=0;i<5;i++){
if(a[i][0]==id){
printf("分配失败!!! 进程ID相同!!!\n");
return ;
}
}
printf("请输入进程所需的内存空间大小:");
scanf("%d",&size);
Allocate(id,size);
return;
}
void del(){
int id;
printf("请输入要退出的进程号:");
scanf("%d",&id);
Release(id);
return;
}
void start(){
int i,j;
partition[0].beginAddress=0;
for(i=0;i<5;i++){
a[i][0]=0;
a[i][1]=0;
}
for(j=0;j<5;j++){
partition[j].id=j+1;
printf("输入地%d个分区大小:",j+1);
scanf("%d",&partition[j].size);
partition[j].beginAddress+=partition[j-1].beginAddress+partition[j-1].size;
partition[j].status='T';
}
}
void dispaly(){
int i;
printf("分区id\t分区大小\t分区首地址\t分区状态(T表示可用,F表示不可用)\n");
for(i=0;i<5;i++){
printf("%d\t%d \t%d \t%c\n",partition[i].id,partition[i].size,partition[i].beginAddress,partition[i].status);
}
}
void table(){
int i;
printf("进程id 内存分区id\n");
for(i=0;i<5;i++){
printf("%d\t%d\n",a[i][0],a[i][1]);
}
}
void run(){
int flag=1;
int choose;
start();
while(flag){
dispaly();
table();
printf("选择你要进行的操作:1: 分配一个进程 2:释放一个进程 3:退出\n");
scanf("%d",&choose);
switch(choose){
case 1: insert();
break;
case 2: del();
break;
case 3: flag=0;
break;
}
}
}
int main(){
run();
}
2、可变式分区分配的存储管理
#include <stdio.h>
#include <stdlib.h>
enum isAllocated{yes, no};
typedef struct Node {
int id;
int start;
int length;
enum isAllocated isallocated;
struct Node* next;
struct Node* prev;
}Node;
Node* head;
void printMenu() {
printf("\n1. 申请内存\n");
printf("2. 释放内存\n");
printf("0. 退出\n");
printf("请选择:");
}
void init(int capacity) {
Node* p = (Node*)malloc(sizeof(Node));
p->id = -1;
p->start = 0;
p->length = capacity;
p->isallocated = no;
p->prev = NULL;
p->next = NULL;
head = p;
}
// 打印空闲分区
void printSpare() {
Node* p = head;
printf("空闲分区如下:\n起始地址\t长度\n---------------------\n");
while (p != NULL) {
if (p->isallocated == no) {
printf("%d\t\t%d\n", p->start, p->length);
}
p = p->next;
}
}
// 申请内存
void getMemory() {
int id, size;
Node* p;
printf("请输入作业号和要申请的内存大小:");
scanf("%d%d", &id, &size);
p = head;
while (p != NULL) {
// 当找到一块长度大于所需空间的空闲分区时
if (p->isallocated == no && p->length > size) {
// 首先新建一个结点
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->id = id;
newNode->length = size;
newNode->isallocated = yes;
newNode->start = p->start;
p->start += size;
p->length -= size;
if (p != head) {
newNode->prev = p->prev;
p->prev->next = newNode;
newNode->next = p;
p->prev = newNode;
}
else {
newNode->prev = NULL;
newNode->next = p;
p->prev = newNode;
head = newNode;
}
break;
}
else if (p->isallocated == no && p->length == size) {
p->id = id;
p->isallocated = yes;
break;
}
p = p->next;
}
if (p == NULL) {
printf("没有足够的内存可以分配了!\n");
}
}
void returnMemory() {
int id;
Node* p;
printf("请输入要释放内存的作业号:");
scanf("%d", &id);
p = head;
while (p != NULL) {
// 根据作业号查找要释放的作业
if (p->id == id) {
p->id = -1;
p->isallocated = no;
// 如果此作业前面还有空闲分区,则与之合并
if (p->prev != NULL && p->prev->isallocated == no) {
p->start = p->prev->start;
p->length += p->prev->length;
p->prev = p->prev->prev;
p->prev->next = p;
}
// 如果此作业后面还有空闲分区,则与之合并
if (p->next != NULL && p->next->isallocated == no) {
p->length += p->next->length;
p->next = p->next->next;
p->next->prev = p;
}
break;
}
p = p->next;
}
if (p == NULL) {
printf("您输入的作业号不存在!\n");
}
}
int main() {
int option;
int capacity;
printf("请先输入内存的容量:");
scanf("%d", &capacity);
init(capacity);
printSpare();
while (1) {
printMenu();
scanf("%d", &option);
switch (option)
{
case 1:
getMemory();
break;
case 2:
returnMemory();
break;
case 0: // 退出
return 0;
default:
break;
}
printSpare(); // 打印空闲分区
}
return 0;
}
3、段页式存储管理的地址转换的模拟程序
#include <stdio.h>
#include <stdlib.h>
#define n 4
//段表
struct Parag
{
int state;
int length;
int PTID;
}parag[4];
struct Page
{
int state;
int MMID;
}page[100];
void print(int did, int ptid)
{
int i;
printf("段表的信息:\n");
printf("段号\t|状态\t|段表大小\t|页表始址|\n");
for(i=0; i < n; i++)
printf("%d\t|%d\t|%d\t\t|%d\t|\n", i, parag[i].state, parag[i].length, parag[i].PTID);
printf("所用表的信息:\n");
printf("页号\t|状态\t|物理块号|\n");
for(i = ptid; i<ptid+parag[did].length; i++)
printf("%d\t|%d\t|%d\t|\n", i-ptid, page[i].state, page[i].MMID);
}
void Init()
{
int i, d=0;
for(i=0; i < n; i++)
{
parag[i].length=i+4;
parag[i].state=1;
parag[i].PTID=d;
d+=parag[i].length;
}
for(i = 0; i < d; i++)
{
page[i].state=1;
page[i].MMID=(i+7)%d;
}
}
void Transform(int DID, int PID, int Address)
{
if(DID >= n)
{
printf("段越界!\n");
return;
}
if(parag[DID].length <= PID)
{
printf("页越界\n");
return;
}
int ptid = parag[DID].PTID;
int ptid2 = ptid+PID;
int mmid = page[ptid2].MMID;
int newAddress = 1024*mmid+Address;
printf("转换前的地址:段号:%d, 页号:%d, 页内地址:%d\n",DID, PID, Address);
print(DID,ptid);
printf("物理地址为:%d", newAddress);
}
int main()
{
int DID, PID, Address;
Init();//初始化页表和段表
printf("段号:\n");
scanf("%d",&DID);
printf("页号:\n");
scanf("%d",&PID);
printf("页内地址:\n");
scanf("%d", &Address);
Transform(DID, PID, Address);
return 0;
}