Índice
Requisitos experimentais
1. Simule a alocação de memória principal do sistema operacional e use o algoritmo de gerenciamento de armazenamento de partições variáveis para projetar o programa de alocação e reciclagem de memória principal sem realmente iniciar a operação de carregamento.
2. Adote o primeiro método de adaptação.
3. Quando um novo trabalho requer carregamento na memória principal, a tabela de áreas livres deve ser verificada para encontrar uma área livre grande o suficiente. Caso a área livre encontrada seja maior que a exigência do trabalho, ela deverá ser dividida em duas partes, sendo uma parte a área ocupada e a outra parte passa a ser área livre.
4. Quando um trabalho é evacuado, se a área devolvida for adjacente a outras áreas livres, ela deverá ser fundida em uma área livre maior e listada na tabela de áreas livres.
5. Execute o programa projetado e produza as alterações nos itens da tabela de estrutura de dados e o status atual da memória.
Código
#include <stdio.h>
#define CAP 1024 //初始化内存容量
#define SYSCAP 100 //系统所占地址,从低位开始
#define N 1000 //进程最大个数
//作业分区
struct USED{
int id,sp,ep,longsize;
}a[N];
//空闲分区
struct FREE{
int id,sp,ep,longsize;
}b[N];
//anum为作业分区块数,bnum为空闲分区块数。初始时作业分区0块,空闲分区有1块
int anum=0,bnum=1;
void Init() //初始化函数,程序开始时只有一个空闲分区
{
b[0].id=0;b[0].sp=SYSCAP;b[0].ep=CAP;b[0].longsize=b[0].ep-b[0].sp;
printf("\n\n--------------最先适应算法--------------\n");
printf("\n内存总量为:%dk\n",CAP);
printf("系统占用容量为:%dk\n",SYSCAP);
printf("---------------------------------------------\n");
printf("空闲分区 起始地址 结束地址 长度\n");
printf(" %d %d %d %d\n",b[0].id,b[0].sp,b[0].ep,b[0].longsize);
printf("---------------------------------------------\n");
}
void Print(int anum,int bnum) //格式化输出作业分区和空闲分区表
{
int i,j;
printf("-----------------作业分区表---------------------\n");
printf("作业分区 起始地址 结束地址 长度\n");
for(i=0;i<anum;i++)
{
printf(" %d %d %d %d\n",a[i].id,a[i].sp,a[i].ep,a[i].longsize);
}
printf("------------------空闲分区表--------------------\n");
printf("空闲分区 起始地址 结束地址 长度\n");
for(i=0;i<bnum;i++)
{
printf(" %d %d %d %d\n",i,b[i].sp,b[i].ep,b[i].longsize);
}
printf("---------------------------------------------\n\n\n");
}
void Put() //进程装入作业
{
int size;
printf("请输入作业%d的大小\n",anum);
scanf("%d",&size);
int i;
for(i=0;i<bnum;i++)
{
b[i].longsize=b[i].ep-b[i].sp; //更新各空闲分区长度
if(b[i].longsize>=size) //找到第一个能放下进程的空闲分区
{
a[anum].id=anum; //空闲区id
a[anum].sp=b[i].sp; //作业内存起始地址等于空闲分区起始地址
a[anum].ep=a[anum].sp+size; //作业的结束地址等于起始地址+作业长度
b[i].sp=b[i].sp+size; //空闲分区起始地址应向后移动size
a[anum].longsize=size; //更新作业地址长度到结构体数组中
b[i].longsize=b[i].ep-b[i].sp;//更新空闲分区地址长度
anum++; //作业数+1
break; //一次只放入一个作业,结束查找
}
}
Print(anum,bnum); //打印结果
}
void Merge() //合并空闲分区,查找结束地址和开始地址重合的地址进行合并
{
int i,j;
if(bnum>=1) //当空闲分区大于等于两个时,才需要检查是否存在可合并的区间
{
for(i=0;i<bnum-1;i++)//从第一个开始检查,到倒数第二个停止
{
if(b[i].ep==b[i+1].sp)
{
bnum--; //存在可合并区间,合并后空闲区间-1
b[i].ep=b[i+1].ep; //结束地址变为合并后的结束地址
b[i].longsize=b[i].ep-b[i].sp;//更新空闲区间长度
for(j=i+1;i<bnum;i++)
{
b[j]=b[j+1]; //删除第i+1个空闲区间
}
}
}
}
}
void Sort(int anum,int bnum)//简单排序函数,将空闲区间按起始地址递增的顺序排序
{
int i,j,min;
for(i=0;i<bnum;i++)
{
min=b[i].sp;
for(j=i;j<bnum;j++)
{
if(b[j].sp<min)
{
min=b[j].sp;
b[N-1]=b[j];
b[j]=b[i];
b[i]=b[N-1];
}
}
}
}
void Remove()//回收作业
{
int i,j,flag=1;//flag是标志位
printf("请输入需要回收的作业:\n");
scanf("%d",&i);
//回收作业存在下面两种情况
for(j=0;j<bnum;j++)//情况1:回收作业后,被回收作业地址刚好能和已存在的空闲分区合并,不需要增加空闲分区块数
{
if(a[i].ep==b[j].sp)
{
b[j].sp=a[i].sp;
b[j].longsize=b[j].ep-b[j].sp;
flag=0; //标志位置0,只能执行一种情况
break;
}
}
if(flag) //情况2:回收作业后,被回收地址不能与已存在的空闲区间合并,需要增加空闲分区块数
{ //创建新的空闲分区
b[bnum].sp=a[i].sp;
b[bnum].ep=a[i].ep;
b[bnum].longsize=a[i].longsize;
b[bnum].id=bnum;
bnum++; //空闲分区个数+1
}
anum--; //移除作业后,作业数-1
for(;i<anum;i++)
{
a[i]=a[i+1];//删除第i个作业分区
a[i].id--; //作业id对应-1
}
Sort(anum,bnum);//排序
Merge();//再次检查合并空闲分区,防止出现增加空闲分区后出现的可合并分区
Print(anum,bnum);//打印结果
}
int main()
{
int input;//input 代表程序运行状态
Init();//初始化,输出
while(1)//写一个死循环
{
printf("装入作业:1 回收作业:0 其他输入结束程序\n");
scanf("%d",&input);
if(input==1)
{
Put();
}else if(input==0)
{
Remove();
}else break;//任意数字退出循环,程序结束
}
return 0;
}
resultado da operação
Análise de código
Defina a quantidade total de memória e memória do sistema como macros (se necessário, basta modificar diretamente os dados da definição da macro)
Defina duas matrizes de estrutura, respectivamente usadas para armazenar e liberar dados de status de partição
anum e bnum são variáveis globais, representando o número de partições de trabalho e partições livres, respectivamente.
#include <stdio.h>
#define CAP 1024 //初始化内存容量
#define SYSCAP 100 //系统所占地址,从低位开始
#define N 1000 //进程最大个数
//作业分区
struct USED{
int id,sp,ep,longsize;
}a[N];
//空闲分区
struct FREE{
int id,sp,ep,longsize;
}b[N];
int anum=0,bnum=1;
A função de inicialização imprime os dados iniciais antes que o programa de algoritmo inicie o processamento. Aqui o subscrito da matriz começa em 0
void Init() //初始化函数,程序开始时只有一个空闲分区
{
b[0].id=0;b[0].sp=SYSCAP;b[0].ep=CAP;b[0].longsize=b[0].ep-b[0].sp;
printf("\n\n--------------最先适应算法--------------\n");
printf("\n内存总量为:%dk\n",CAP);
printf("系统占用容量为:%dk\n",SYSCAP);
printf("---------------------------------------------\n");
printf("空闲分区 起始地址 结束地址 长度\n");
printf(" %d %d %d %d\n",b[0].id,b[0].sp,b[0].ep,b[0].longsize);
printf("---------------------------------------------\n");
}
Imprima os resultados e imprima os dados da estrutura correspondentes em ordem.
void Print(int anum,int bnum) //格式化输出作业分区和空闲分区表
{
int i,j;
printf("-----------------作业分区表---------------------\n");
printf("作业分区 起始地址 结束地址 长度\n");
for(i=0;i<anum;i++)
{
printf(" %d %d %d %d\n",a[i].id,a[i].sp,a[i].ep,a[i].longsize);
}
printf("------------------空闲分区表--------------------\n");
printf("空闲分区 起始地址 结束地址 长度\n");
for(i=0;i<bnum;i++)
{
printf(" %d %d %d %d\n",i,b[i].sp,b[i].ep,b[i].longsize);
}
printf("---------------------------------------------\n\n\n");
}
Algoritmo principal: carregue o trabalho na memória (os métodos de implementação específicos estão todos escritos nos comentários, se você ainda não entendeu, pode me enviar uma mensagem privada)
void Put() //进程装入作业
{
int size;
printf("请输入作业%d的大小\n",anum);
scanf("%d",&size);
int i;
for(i=0;i<bnum;i++)
{
b[i].longsize=b[i].ep-b[i].sp; //更新各空闲分区长度
if(b[i].longsize>=size) //找到第一个能放下进程的空闲分区
{
a[anum].id=anum; //空闲区id
a[anum].sp=b[i].sp; //作业内存起始地址等于空闲分区起始地址
a[anum].ep=a[anum].sp+size; //作业的结束地址等于起始地址+作业长度
b[i].sp=b[i].sp+size; //空闲分区起始地址应向后移动size
a[anum].longsize=size; //更新作业地址长度到结构体数组中
b[i].longsize=b[i].ep-b[i].sp;//更新空闲分区地址长度
anum++; //作业数+1
break; //一次只放入一个作业,结束查找
}
}
Print(anum,bnum); //打印结果
}
Algoritmo principal: recicle o trabalho e recicle a memória ocupada pelo trabalho em uma área livre
Vamos falar sobre por que existem duas situações em que as operações de reciclagem estão escritas no código
Caso 1:
Durante a reciclagem do trabalho, inserir a partição livre pode ser mesclada diretamente com a partição livre sem adicionar uma nova partição livre (conforme mostrado abaixo)
Após reciclar e mesclar:
Caso 2:
Durante a reciclagem do trabalho, ao entrar na partição livre, ela não pode ser mesclada diretamente com a partição livre, e uma nova partição livre precisa ser adicionada (conforme mostrado na figura abaixo, o bloco amarelo é a partição do trabalho a ser reciclada)
Após reciclar e mesclar:
void Remove()//回收作业
{
int i,j,flag=1;//flag是标志位
printf("请输入需要回收的作业:\n");
scanf("%d",&i);
//回收作业存在下面两种情况
for(j=0;j<bnum;j++)//情况1:回收作业后,被回收作业地址刚好能和已存在的空闲分区合并,不需要增加空闲分区块数
{
if(a[i].ep==b[j].sp)
{
b[j].sp=a[i].sp;
b[j].longsize=b[j].ep-b[j].sp;
flag=0; //标志位置0,只能执行一种情况
break;
}
}
if(flag) //情况2:回收作业后,被回收地址不能与已存在的空闲区间合并,需要增加空闲分区块数
{ //创建新的空闲分区
b[bnum].sp=a[i].sp;
b[bnum].ep=a[i].ep;
b[bnum].longsize=a[i].longsize;
b[bnum].id=bnum;
bnum++; //空闲分区个数+1
}
anum--; //移除作业后,作业数-1
for(;i<anum;i++)
{
a[i]=a[i+1];//删除第i个作业分区
a[i].id--; //作业id对应-1
}
Sort(anum,bnum);//排序
Merge(); //再次检查合并空闲分区,防止出现增加空闲分区后出现的可合并分区
Print(anum,bnum);//打印结果
}
Algoritmo de classificação, reclassificando endereços de grandes para pequenos após cada reciclagem (esta etapa é obrigatória)
A reciclagem do trabalho é arbitrária. Se os blocos de endereços altos forem reciclados primeiro sem classificação, os endereços altos serão alocados primeiro na próxima vez que a partição livre for recuperada. Obviamente, isso não está de acordo com a definição do melhor algoritmo de adaptação.
void Sort(int anum,int bnum)//简单排序函数,将空闲区间按起始地址递增的顺序排序
{
int i,j,min;
for(i=0;i<bnum;i++)
{
min=b[i].sp;
for(j=i;j<bnum;j++)
{
if(b[j].sp<min)
{
min=b[j].sp;
b[N-1]=b[j];
b[j]=b[i];
b[i]=b[N-1];
}
}
}
}
Função mesclar, verificar e depois mesclar. Esta é na verdade a terceira situação que ocorre após o processamento das duas situações anteriores.
Após reciclar e mesclar:
void Merge() //合并空闲分区,查找结束地址和开始地址重合的地址进行合并
{
int i,j;
if(bnum>=1) //当空闲分区大于等于两个时,才需要检查是否存在可合并的区间
{
for(i=0;i<bnum-1;i++)//从第一个开始检查,到倒数第二个停止
{
if(b[i].ep==b[i+1].sp)
{
bnum--; //存在可合并区间,合并后空闲区间-1
b[i].ep=b[i+1].ep; //结束地址变为合并后的结束地址
b[i].longsize=b[i].ep-b[i].sp;//更新空闲区间长度
for(j=i+1;i<bnum;i++)
{
b[j]=b[j+1]; //删除第i+1个空闲区间
}
}
}
}
}
função principal. Chame a função de processamento correspondente por meio da entrada do usuário
int main()
{
int input;//input 代表程序运行状态
Init();//初始化,输出
while(1)//写一个死循环
{
printf("装入作业:1 回收作业:0 其他输入结束程序\n");
scanf("%d",&input);
if(input==1)
{
Put();
}else if(input==0)
{
Remove();
}else break;//任意数字退出循环,程序结束
}
return 0;
}
Obrigado pela leitura ~ Se você tiver alguma boa sugestão, pode comentar ou me enviar uma mensagem privada ~ Se não entender alguma coisa, também pode me enviar uma mensagem privada ~
Se você achar útil, por favor, dê um like e saia ~