当前位置:首页 » 服务存储 » 存储器首次适用算法流程图
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

存储器首次适用算法流程图

发布时间: 2023-08-07 02:08:32

① 2.采用首次适应算法和最佳适应算法模拟实现可变分区管理。

#define MAX 100
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int b;//存放进程本次结束时的时间
void main()
{
int i,N,t,k;
int a[MAX];//存放进程的剩余时间
int cnt[MAX];//存放进程调度次数
printf("请输入进程数N:");
scanf("%d",&N);
printf("\n请输入时间片t大小:");
scanf("%d",&t);
printf("\n请依次输入各个进程的服务时间");
for(i=0;i<N;i++)
{
scanf("%d",&a[i]);
cnt[i]=0;
}
printf("被调度进程\t进程调度次数 \t本次运行时间结果\t剩余时间\n");
k=1;
while(k)
{
for(i=0;i<N;i++)
{
if(a[i]!=0)
if(a[i]>=t)
{
a[i]-=t;
b+=t;
cnt[i]=cnt[i]+1;
printf("\n\t%d\t\t%d\t\t%d\t\t%d",i+1,cnt[i],b,a[i]);
}
else
{
b=b+a[i];
cnt[i]=cnt[i]+1;
a[i]=0;
printf("\n\t%d\t\t%d\t\t%d\t\t%d",i+1,cnt[i],b,a[i]);
}
else continue;
}
for(i=0;i<N;i++)
if(a[i]!=0)
{ k=1;break;}
else continue;
if(i>=N)
k=0;
}
printf("\n");
printf("进程全部运行完成!");
printf("\n");

}

② 主存空间的分配和回收,

#include "iostream.h"
#include "iomanip.h"

#define nofreearea 2
#define noadequacyarea 3
#define allocated 4

#define noprocess 2
#define nosuchprocess 3
#define reclaimed 4

typedef struct TUN
{
int address;
int size;
char name;
struct TUN *next;
} usedarea , *usedtable;

typedef struct TFN
{
int address;
int size;
struct TFN *next;
} freearea, *freetable;

usedtable usedTable = NULL;
freetable freeTable = NULL;

int alloc( char processname , int processsize )
{

if( freeTable == NULL )
return 1;
freetable p = freeTable;
freetable q = p;

while( p != NULL && p->size < processsize )
{
q = p;
p = p->next;
}

if( p == NULL )
return 3;

usedtable x = new usedarea;
x->address = p->address;
x->size = processsize;
x->name = processname;
x->next = NULL;

if( p->size > processsize )
{
p->size -= processsize;
p->address += processsize;
}

else
{
if( p == freeTable )
freeTable = NULL;
else
q->next = p->next;
delete p;
}

usedtable r = usedTable;
usedtable t = r;

while( r != NULL && r->address < x->address )
{
t = r;
r = r->next;
}

if( usedTable == NULL )
usedTable = x;
else
{
x->next = r;
t->next = x;
}

return 4;
}

int Reclaim( char processname )
{
if( usedTable == NULL )
return 1;
usedtable p = usedTable;
usedtable q = p;
while( p != NULL && p->name != processname )
{
q = p;
p = p->next;
}

if( p == NULL )
return 3;

freetable r = freeTable;
freetable t = r;
freetable x;
while( r != NULL && r->address < p->address )
{
t = r;
r = r->next;
}

x = new freearea;
x->address = p->address;
x->size = p->size;
x->next = NULL;

if( r == freeTable )
{
x->next = r;
freeTable = x;
t = freeTable;
}
else
{
x->next = r;
t->next = x;
}

while( t->next != NULL && t->address + t->size == t->next->address )
{
t->size += t->next->size;
r = t->next;
t->next = t->next->next;
delete r;
}

if( p == usedTable )
{
usedTable = usedTable->next;
}
else
q->next = p->next;
delete p;

return 4;
}

int Init()
{
freeTable = new freearea;
freeTable->address = 0;
freeTable->size = 128;
freeTable->next = NULL;
return 1;
}

void processrequest()
{
char processname;
int processsize;
cout<<"...................."<<endl;
cout<<"作业名: ";
cin >> processname;
cout<<"作业长度: ";
cin >> processsize;
if(processsize<=128)
{int i;
if( alloc( processname , processsize) == 4 )
{
i=i+processsize;
if(i>128)
{cout<<"该作业超出空间"<<endl;
}
if(i<=128)
cout<<"该作业已成功获得所需空间"<<endl;
i=i+processsize;
cout<<"........................................"<<endl;

}
else
cout<<"该作业超出空间,没有获得所需空间"<<endl;
cout<<"........................................"<<endl;
return;
}
if(processsize>128)
{cout<<"该作业超出空间"<<endl;
cout<<"........................................"<<endl;
}

}

void processreclaim()
{
int processname;
cout<<"...................."<<endl;
cout<<"作业名: ";
cin >>processname;
int result = Reclaim( processname );
if( result == 4 )
cout<<"该作业已成功回收"<<endl;
else if( result == 2 || result == 1 )
cout<<"系统没有作业或该作业不存在"<<endl;
cout<<"...................."<<endl;

}

void freeTablePrint()
{
cout<<endl<<endl<<endl<<"***********************************"<<endl;
cout<<setw(10)<<"address"<<setw(10)<<"length"<<setw(10)<<"state"<<endl<<endl;
freetable p = freeTable;
usedtable q = usedTable;
int x , y;
while( p || q )
{
if( p )
x = p->address;
else
x = 0x7fffffff;
if( q )
y = q->address;
else
y = 0x7fffffff;

if( x < y )
{
cout<<setw(10)<<p->address<<setw(10)<<p->size<<setw(10)<<"空闲"<<endl;
p = p->next;
}
if( x > y )
{
cout<<setw(10)<<q->address<<setw(10)<<q->size<<setw(10)<<"已分配"<<setw(10)<<"ID="<<q->name<<endl;
q = q->next;
}
}
cout<<endl<<endl<<endl<<"************************************"<<endl<<endl<<endl;

}

void main()
{
Init();
int choose;
bool exitFlag = false;
while( !exitFlag )
{

cout<<"************************0 - 退出 ************************"<<endl;
cout<<"************************1 - 分配主存 ************************"<<endl;
cout<<"************************2 - 回收主存 ************************"<<endl;
cout<<"************************3 - 显示主存 ************************"<<endl<<endl<<endl;
cout<<"************************选择所要执行的操作:";
cin>>choose;
switch( choose )
{
case 0:
exitFlag = true;
break;
case 1:
processrequest();
break;
case 2:
processreclaim();
break;
case 3:
freeTablePrint();
break;
}
}
}

存储器管理的连续分配存储管理方式有哪些

连续分配方式.它是指为了一个用户程序分配一个连续的内存空间.可以分为单一连续分配、固定分区分配、动态分区分配以及动态重定位分区分配四种方式。不过今天我们讲的是固定分区分配和动态分区分配。
固定分区分配是最简单的一种可运行多道程序的存储管理方式。 一、基本思想:在系统中把用户区预先划分成若干个固定分区(每个分区首地址固定,每个分区长度是固定),每个分区可供一个用户程序独占使用。注意:每个分区大小可以相同,也可以不相同。 二、主存分配与回收:借助主存分配表。 三、地址转换(静态重定位):物理地址=分区起始地址+逻辑地址。其中划分分区方法包括分区大小相等和分区大小不等。
动态分区分配是根据进程的实际需要,动态地为之分配内存空间。一、基本思想:按用户程序需求动态划分主存供用户程序使用。(每个分区首地址是动态的,每个分区的长度也是动态的) 二、主存分配与回收-->(1)未分配表(登记未分配出去的分区情况);(2)已分配表(登记已经分配出去的分区情况)。 三、地址转换:物理地址=分区起始地址+逻辑地址。 四、分区分配算法:从空闲分区中选择分区分www.hbbz08.com 配给用户程序的策略。 (1)首次适应算法(最先适应)顺序查询为分配表,从表中找出第一个可以满足作业申请的分区划分部分分配给用户作业。 (2)循环首次适应算法 (3)最佳适应算法:从空闲分区中找出一个能满足用户作业申请的最小空闲分区划分给用户作业使用(有利于大作业执行) (4)最坏适应算法:从空闲分区中挑最大的分区划分给用户程序使用(有利于中、小作业执行)

④ 内存管理

在一段时间内,程序的执行仅限于某个部分,相应地,它所访问的存储空间也局限于某个区域。

局部性原理的 分类

将编译后的目标模块装配成一个可执行程序。

可执行程序以 二进制可执行文件 的形式存储在磁盘上。

链接程序的 任务

程序的链接,可划分为:

重定位 :将逻辑地址(相对地址)转换为物理地址(绝对地址)的过程。

物理地址 = 逻辑地址 + 程序在内存中的起始地址

程序的装入,可划分为:

任何时刻主存储器 最多只有一个作业

每个分区 大小固定不变 :分区大小相等、分区大小不等。

每个分区可以且 仅可以装入一个作业

使用 下限寄存器 上限寄存器 来保存当前作业的起始位置和结束位置。

使用 固定分区说明表 区分各分区的状态。

分区 大小不是预先固定的 ,而是按作业(进程)的实际需求来划分的。

分区 个数也不是预先固定的 ,而是由装入的作业数决定的。

使用 空闲分区表 说明空闲分区的位置。

使用 空闲分区链 说明空闲分区的位置。

首次适应算法的 过程

外部碎片:空闲内存 没有在 分配的 进程 中。

内部碎片:空闲内存 分配的 进程 中。

上次找到的 空闲分区的 下一个 空闲分区开始查找。

优点:空闲区分布均匀、查找开销较小。

缺点:缺乏大空闲区。

最佳适应算法的 过程

优点:提高内存利用率。

注意点:每次在进行空闲区的修改前,需要先进行 分区大小递增 的排序。

:将一个 进程 逻辑地址空间 分成若干个 大小相等

页框 :将 物理内存空间 分成与页大小相同的若干个 存储块

分页存储 :将进程的若干 分别装入多个 可以不相邻 页框 中。

页内碎片 :进程 最后一页 一般装不满一个页框,形成 页内碎片

页表 :记录描述页的各种数据,实现从 页号 页框号 的映射。

注意: 页内偏移量 的单位是 字节

分页地址变换指是: 逻辑地址 通过 地址变换机构 变换为 物理地址

分页地址变换的 过程

操作系统在修改或装入页表寄存器的值时,使用的是 特权级 指令。

页大小:512B ~ 4KB,目前的计算机系统中,大多选择 4KB 大小的页。

页大小的 选择因素

快表也称为“转换后援缓冲”,是为了提高CPU访问速度而采用的专用缓存,用来存放 最近被访问过的页表项

英文缩写:TLB。

组成: 键和值

在TLB中找到某一个页号对应的页表项的百分比称为 TLB命中率

在TLB中找到所需要的页表项时:

有效访问时间 = 一次访问TLB 的时间 + 一次访问内存 的时间(访问内存读写数据或指令)

不能 在TLB中找到所需要的页表项时:

有效访问时间 = 一次访问TLB 的时间 + 两次访问内存 的时间(一次访问内存页表,一次访问内存读写数据或指令)

将页表再分页,形成两级或多级页表,将页表离散地存放在物理内存中。

在进程切换时,要运行的进程的页目录表歧视地址被写入 页表寄存器

在二级分页系统中,为页表再建立一个页目录表的目的是为了能在地址映射时得到页表在物理内存中的地址,在页目录表的表项中存放了每一个 页表 在物理内存中所在的 页框号

虚拟存储器 :是指具有 请求调入功能 置换功能 ,能 从逻辑上对内存容量进行扩充 的一种存储系统。

请求调入 :就是说,先将进程一部分装入内存,其余的部分什么时候需要,什么时候请求系统装入。

置换 :如果请求调入时,没有足够的内存,则由操作系统选择一部分内存中的进程内容移到外存,以腾出空间把当前需要装入的内存调入。

为了实现请求分页,需要:

保证进程正常运行的所需要的最小页框数。

最小页框数与进程的大小没有关系,它与计算机的 硬件结构 有关,取决于 指令的格式、功能和寻址方式

内存不够时,从进程本身选择淘汰页,还是从系统中所有进程中选择?:

采用什么样的算法为不同进程分配页框?:

常用的两种 置换策略 局部置换 全局置换

从分配给进程的页框数量上看,常使用的两种 分配策略 固定分配 可变分配

用新调入的页替换 最长时间没有访问 的页面。

找到 未来最晚被访问 的那个页换出。

,P为缺页率。

有效访问时间与缺页率成 正比 ,缺页率越高,有效访问时间越长,访问效率越低。

工作集 :某段时间间隔里,进程实际要访问的页的集合。

引入工作集的 目的 :降低缺页率,提高访问内存效率。

抖动 :运行进程的大部分时间都用于页的换入换出,几乎不能完成任何有效果工作的状态。

抖动的 产生原因

抖动的 预防方法

在分段存储管理的系统中,程序使用 二维 的逻辑地址,一个数用来表示 ,另一个数用来表示 段内偏移量

引入分段的 目的

引入分段的 优点

进程的地址空间被划分成 若干个段

每个段定义了一组逻辑信息,每个段的大小由相应的逻辑信息组的长度确定, 段的大小不一样 ,每个段的逻辑地址从0开始,采用一段 连续的地址空间

系统为每个段分配一个 连续的物理内存区域 ,各个 不同的段可以离散 地放入物理内存不同的区域。

系统为 每个进程建立一张段表 ,段表的每一个表项记录的信息包括: 段号、段长和该段的基址 ,段表存放在内存中。

分段的 逻辑地址结构

段表是由操作系统维护的用于支持分段存储管理 地址映射 的数据结构。

每个进程有一个段表,段表由段表项构成。每个段表项包括: 段号、段长(段的大小)和该段的基址(段的起始地址)

若已知逻辑单元的地址为 S:D (段号:段内偏移量),求相应物理地址的步骤如下:

相同点 :分页和分段都属于 离散 分配方式,都要通过数据结构与硬件的配合来实现 逻辑地址到物理地址 的映射。

不同点

将用户进程的逻辑空间 先划分为若干个段 每个段再划分成若干个页

进程以页为单位在物理内存中 离散 存放,每个段中被离散存放的页具有 逻辑相关性

为了实现地址映射,操作系统为 每个进程建立一个段表 ,再为 每个段建立一个页表

进程段表的段表项组成:

满足以下条件的两个块称为 伙伴

⑤ 求首次适应算法的c语言程序!(计算机操作系统的)

最佳适应算法C++程序:

struct list // 初始化数据的结构体
{
int num;
int adr;
int end;
int size;
}s[]={{1,1000,2999,2000},{2,500,799,300},{3,3500,3699,200},{4,4000,4499,500}}; // 初始化空闲分区

/*void print(struct list *p,int n) // print函数作用输出结果
{
int flag1=1;
int flag2=1;
int i,j=0;
cout<<"-------------------------------------\n";
for(i=0;i {
if(p->size==0) // 控制不输出size=0的空闲块
{
flag2=0;
j++;
continue;
}
else
flag2=1;
if(p->size!=0&&flag2!=0)
{
flag1=0;
cout<<"序号:"<num-j/*输出的序号仍然是从1开始*//*<<" 起始位置:"<adr<<" 终止位置:"<end<<" 空闲块大小:"<size< }
}
if(flag1==1) // 当所有的空闲块正好被分配完时
cout<<"\n空闲内存已被分配完,请回收!\n";
cout<<"-------------------------------------\n";
}*/
void print(struct list a[],int n) // print函数作用输出结果
{
int i;
cout<<"-------------------------------------\n";
if(a[0].size==0)
{
for(i=0;i {
a[i].adr=a[i+1].adr;
a[i].size=a[i+1].size;
a[i].end=a[i+1].end;
}
k=k-1;
}
if(k==0)
cout<<"\n空闲块已经分配完毕,需要再分配,请回收!\n";
for(i=0;i cout<<"序号:"< cout<<"-------------------------------------\n";
}

未完。请自己从参考资料上复制。

⑥ 文件存储空间管理

  上篇文章介绍了文件的物理结构并介绍了文件分配的三种方式——连续分配、链接分配和索引分配。
  本文介绍操作系统对文件存储空间的管理。
本文内容

  存储空间的划分: 将物理磁盘划分为一个个文件卷(逻辑卷、逻辑盘)
  在存储空间初始化时,需要将各个文件卷划分为目录区、文件区。

  有些系统支持超大型文件,可支持由多个物理磁盘组成一个文件卷。

  空闲表法:即用一张表记录磁盘中空闲的盘块。空闲表的表项由 空闲盘的起始块号 空闲盘块数 组成。如下图所示

  如何分配磁盘块:与内存管理中的动态分区分配类似,为一个文件分配连续的存储空间。同样可以采用 首次适应算法、最佳适应算法、最坏适应算法,临近适应算法 来决定要为文件分配哪些区间。
   空闲表法适用于连续分配方式。
  例如,如果新创建的文件请求3个块,按照首次适用算法,从10号块开始有5个连续的块可以满足需求,所以把10、11、12三个块分配给文件,分配后的空闲盘块表如下

  这里以回收区前后都是空闲区为例,磁盘是第一幅图的状态,如果回收21、22号磁盘块,那么回收后的空闲盘块表如下图所示。

  空闲链表法分为两种: 空闲盘块链和空闲盘区链

  下图分别表示空闲盘块链和空闲盘区链。

  操作系统保存着 链头、链尾指针。
  如何分配:如过某文件申请K个盘块,则从链头开始依次摘下K个盘块分配,并修改空闲链的链头指针。
  如何回收:回收的盘块依次挂到链尾,并修改空闲链的链尾指针。
  下图表示分配了3个盘块

  从上面可以看出,空闲盘块法适用于 离散分配 的物理结构。为文件分配多个盘块时可能要重复多次操作。

  操作系统保存着 链头、链尾指针
  如何分配:若某文件申请K个盘块,由于空闲盘区链将连续的盘块组成一个盘区,所以若某个盘区大小满足可以实现一次分配,同样可以采用首次适用、最佳适用等算法,从链头开始检索,按照一定的规则找到一个大小符合要求的空闲盘区分配给文件。若没有合适的连续空闲块,也可以将不同的盘区的盘同时分配给一个文件,同样分配后也需要修改相应的指针链和盘区大小等数据。

  如何回收:若回收区和某个空闲盘区相邻,则需要将回收区合并到空闲盘区中。若回收区没有和任何空闲区相邻,将回收区作为一个单独的一个空闲盘区挂到链尾。同样也需要修改链表指针和盘区大小等信息。
  下图表示按照首次适用算法分配3个盘区

  从上面可以看出,空闲盘区链对 离散分配、连续分配 都适用。为一个文件分配多个盘块时 效率更高

  位示图:磁盘内存被划分为一个个磁盘块,可以用二进制位对应一个盘块。“0”代表盘块空闲,“1”代表盘块已分配。位示图一般用连续的“字”来表示,下图中一个字的字长是16位,字中的每一位对应一个盘块。因此可以用(字号,位号)对应一个盘块号。

  如何分配:若文件需要K个块,①顺序扫描位示图,找到K个相邻或不相邻的“0”;②根据字号、位号算出对应的盘块号,将相应的盘块分配给文件;③将相应的位设置为“1”。

  如何回收:①根据回收的盘块号计算出对应的字号、位号;②将相应的二进制位设置为“0”。

  从上面可以看出:位示图法对 连续分配和离散分配 都适用。

  空闲表法、空闲链表法不适用大型文件系统,因为空闲表或空闲联保可能过大。UNIX系统中采用了 成组链接法 对磁盘空闲块进行管理。这是将上述两种方法相结合的而形成的一种空闲管理方法。
  文件卷的目录区中专门用一个磁盘块作为 超级块 ,当系统启动时需要将 超级块读入内存 。并且要保证与外存中的“超过块”的数据一致。

  内存的分配过程:分配过程是从栈顶取出一空闲盘块号,将与之对应的盘块分配给用户,然后将栈顶指针下移一格,若该盘块号已是栈底(即第一个盘块),这是当前栈中最后一个可分配的盘块号。由于在该盘块号所对应的盘块中记有下一组可用的盘块号,因此,不能直接将它分配掉,需要将它记录的下一组信息保存下来,所以比须调用磁盘读过程,将栈底盘块号所对应盘块的内容读入栈中,作为新的盘块号栈的内容,并把原栈底对应的盘块分配出去(其中的有用数据已读入栈中)。然后,再分配一相应的缓冲区(作为该盘块的缓冲区)。最后,把栈中的空闲盘块数减1 并返回。

  下面举例说明
  如果此时新建一个文件需要一个磁盘块,那么此时第一组有100个空闲块,所以是足够分配的,将栈顶的盘块号即201号盘块对应的盘块分配出去,如下图

  如果此时又创建一个新的文件,需要99个磁盘块,就需要将剩下的99个盘块全部分配出去,但是此时300号盘块记录了下一组信息,如果分配出去,信息就是丢失,所以需要将300号盘块从外存(磁盘)读入内存,将300号盘块记录的信息,写入空闲盘块号栈,然后才能将这99块空闲块分配出去。具体过程如下图所示

  
  内存的回收过程:在系统回收空闲盘块时,须调用盘块回收过程进行回收。它是将回收盘块的盘块号记入空闲盘块号栈的顶部,并执行空闲盘块数加 1 操作。当栈中空闲盘块号数目已达 100 时,表示栈已满,便将现有栈中的100 个盘块号记入新回收的盘块中,再将其盘块号作为新栈底。

  以分配的第一个图为例,201盘块被分配出去了,如果此刻有个文件被删除了,其占用的盘块是199号,系统需要回收这个盘块,发现此时空闲盘块号栈中记录空闲块数为99,直接将盘块号记录栈顶,将空闲盘块数加1即可。

  如果此时又有一个文件被删除了,其占用的盘块是190,此时空闲盘块号数已经达到100了,就需要将现在空闲盘块栈中信息记入新回收的块中。