一、实验内容:
主存是中央处理机能直接存取指令和数据的存储器。能否合理而有效地使用主存,在很大程度上将影响到整个计算机系统的性能。实现主存空间的分配和回收。
二、实验目的:
本实验主要让大家熟悉主存的各种分配和回收。所谓分配,就是解决多道作业或多进程如何共享主存空间的问题。所谓回收,就是当作业运行完成时,将作业或进程所占用的主存空间还给系统。主存的分配与回收的实现是与主存储器的管理方式有关的。通过本实验,帮助学生理解在不同的存储器管理方式下,如何实现主存空间的分配与回收。
算法流程图:
本次实验采用PyCharm 2020.1 软件进行实现。
为了能够展示三种方案的不同效果,所以采用了主屏和操作键位分开的操作,即采用mainpanel做演示主界面,subpanel做操作副界面。
主存空间的分配与回收操作主界面:
主存空间的分配与回收操作副界面:
为了进行演示,我们初始化设定5个空间,大小分别为100,500,200,300,600,方便之后进行演示。
为了方便进行对比,我们采用 212 KB, 417 KB, 112 KB, 426 KB大小的作业依次进行分配进行演示。
1.点击首次适应算法:
每点击一次申请就输入一个作业,输入所有作业,观察主屏和控制台的情况:
结果发现最后D作业没有足够空间,只能进行等待。
1.点击最佳适应算法:
每点击一次申请就输入一个作业,输入所有作业,观察主屏和控制台的情况:
结果所有作业都分配到了空间。
此时释放作业C:
作业C成功释放。
1.点击最坏适应算法:
每点击一次申请就输入一个作业,输入所有作业,观察主屏和控制台的情况:
最后结果显示D作业大小为426,大于最大的空间300,所以没有进行分配。
import operator
import tkinter
import random
CNT,counts = 512,0
ans=[]
class Task:
# beginTime, waitTime, finishTime, runTime, weightRunTime, ratio
name = ''
start = 0
end = 0
size = 0
flag = 0
def __init__(self, name , start , end, flag):
self.name = name
self.start = start
self.end = end
self.flag = flag
def output():
global ans,counts
tit = "名称\t标识\t起址\t长度\t状态"
l1 = tkinter.Label(mainpanel, text=tit)
l1.place(x=40,y=200,width=500, height=30)
for i in range(0,counts):
strflag,strname="",""
if(ans[i].flag==1):
strflag="未分配"
strname="P"
else:
strflag="已分配"
strname=ans[i].name
if(i==0):
outs = ' {} \t{} \t{} \t{} \t{} '.format(strname, i,0,ans[i].end,strflag)
else:
outs = ' {} \t{} \t{} \t{} \t{} '.format(strname, i,ans[i-1].start+ans[i-1].end,ans[i].end,strflag)
l2 = tkinter.Label(mainpanel, text=outs)
l2.place(x=-100, y=240 + 20 * (i + 1), width=800, height=10)
if(i>=counts):
break
def buttonInitClick():
global CNT, counts, ans
idx=0
for i in range(20):
outs = ' \t \t \t \t'
l2 = tkinter.Label(mainpanel, text=outs)
l2.place(x=-100, y=240 + 20 * (idx + 1), width=800, height=10)
idx+=1
counts=0
ans=[]
single=Task('',0,0,1)
ans=[single]*CNT
counts += 1
ans[0]=Task('P',0,100,1)
counts += 1
ans[1]=Task('P',100,500,1)
counts += 1
ans[2]=Task('P',100+500,200,1)
counts += 1
ans[3] = Task('P', 600 + 200, 300, 1)
counts += 1
ans[4] = Task('P', 800 + 300, 600, 1)
output()
def buttonFirstFitApplyClick():
global counts,ans
applyflag=0
print("请输入申请的进程名称及资源数")
cname,num=input().split()
num=int(num)
for i in range(0,counts):
if(ans[i].flag==1):
if(ans[i].end>=num):
item = Task(cname,ans[i].start,num,0)
ans[i].start=item.end+ans[i].start
ans[i].end=ans[i].end-item.end
counts+=1
applyflag=1
ans.insert(i,item)
break
if(applyflag==1):
print("申请成功")
else:
print("没有足够大的空闲空间")
output()
def buttonBestFitApplyClick():
global counts, ans
flagnum,flagidx,applyflag = 100000000,0,0
print("请输入申请的进程名称及资源数")
cname, num = input().split()
num = int(num)
for i in range(0, counts):
if (ans[i].flag == 1):
if (ans[i].end >= num):
if(ans[i].end-num<flagnum):
flagidx=i
flagnum=ans[i].end-num
applyflag = 1
if (applyflag == 1):
item = Task(cname, ans[flagidx].start, num, 0)
ans[flagidx].start = item.end + ans[flagidx].start
ans[flagidx].end = ans[flagidx].end - item.end
counts += 1
ans.insert(flagidx, item)
print("申请成功")
else:
print("没有足够大的空闲空间")
output()
def buttonWorstFitApplyClick():
global counts, ans
flagnum,flagidx,applyflag = -100000000,0,0
print("请输入申请的进程名称及资源数")
cname, num = input().split()
num = int(num)
for i in range(0, counts):
if (ans[i].flag == 1):
if (ans[i].end >= num):
if(ans[i].end-num>flagnum):
flagidx=i
flagnum=ans[i].end-num
applyflag = 1
if (applyflag == 1):
item = Task(cname, ans[flagidx].start, num, 0)
ans[flagidx].start = item.end + ans[flagidx].start
ans[flagidx].end = ans[flagidx].end - item.end
counts += 1
ans.insert(flagidx, item)
print("申请成功")
else:
print("没有足够大的空闲空间")
output()
def buttonReleaseClick():
global counts,ans
releaseflag=0
print("请输入释放的进程名称及资源数")
cname,num=input().split()
num = int(num)
for i in range(0, counts):
if(ans[i].name==cname):
if(num==ans[i].end):
ans[i].name='P'
ans[i].flag=1
releaseflag=1
break
if(releaseflag==1):
print("释放成功")
else:
print("释放失败")
output()
def buttonFirstFitClick():
subpanel = tkinter.Tk()
subpanel.title('首次适应算法')
subpanel.geometry('500x300+500+100')
subPress1(subpanel)
subpanel.mainloop()
def buttonBestFitClick():
subpanel = tkinter.Tk()
subpanel.title('最佳适应算法')
subpanel.geometry('500x300+500+100')
subPress2(subpanel)
subpanel.mainloop()
def buttonWorstFitClick():
subpanel = tkinter.Tk()
subpanel.title('最坏适应算法')
subpanel.geometry('500x300+500+100')
subPress3(subpanel)
subpanel.mainloop()
def press():
buttonFirstFit = tkinter.Button(mainpanel, text='首次适应算法', command=buttonFirstFitClick)
buttonFirstFit.place(x=50, y=50, width=100, height=100)
buttonBestFit = tkinter.Button(mainpanel, text='最佳适应算法', command=buttonBestFitClick)
buttonBestFit.place(x=200, y=50, width=100, height=100)
buttonWorstFit = tkinter.Button(mainpanel, text='最坏适应算法', command=buttonWorstFitClick)
buttonWorstFit.place(x=350, y=50, width=100, height=100)
def subPress1(subpanel):
buttonInit = tkinter.Button(subpanel, text='初始化', command=buttonInitClick)
buttonInit.place(x=50, y=50, width=100, height=100)
buttonApply = tkinter.Button(subpanel, text='申请', command=buttonFirstFitApplyClick)
buttonApply.place(x=200, y=50, width=100, height=100)
buttonFree = tkinter.Button(subpanel, text='释放',command=buttonReleaseClick)
buttonFree.place(x=350, y=50, width=100, height=100)
# buttonDestroy = tkinter.Button(subpanel, text='退出')
# buttonDestroy.place(x=500, y=50, width=100, height=100)
def subPress2(subpanel):
buttonInit = tkinter.Button(subpanel, text='初始化', command=buttonInitClick)
buttonInit.place(x=50, y=50, width=100, height=100)
buttonApply = tkinter.Button(subpanel, text='申请', command=buttonBestFitApplyClick)
buttonApply.place(x=200, y=50, width=100, height=100)
buttonFree = tkinter.Button(subpanel, text='释放',command=buttonReleaseClick)
buttonFree.place(x=350, y=50, width=100, height=100)
def subPress3(subpanel):
buttonInit = tkinter.Button(subpanel, text='初始化', command=buttonInitClick)
buttonInit.place(x=50, y=50, width=100, height=100)
buttonApply = tkinter.Button(subpanel, text='申请', command=buttonWorstFitApplyClick)
buttonApply.place(x=200, y=50, width=100, height=100)
buttonFree = tkinter.Button(subpanel, text='释放',command=buttonReleaseClick)
buttonFree.place(x=350, y=50, width=100, height=100)
mainpanel = tkinter.Tk()
mainpanel.title('主存空间的分配与回收')
mainpanel.geometry('720x1080+500+100')
press()
mainpanel.mainloop()
结果分析
实验结果统计图:
结果发现,在最佳适应的情况下,所有的作业都能及时得到空间的分配,其他两种算法并不能将所有的作业都及时得到分配。在演示效果上最佳适应算法优于其他的算法。
算法优缺点
一、首次适应算法(First Fit):该算法从空闲分区链首开始查找,直至找到一个能满足其大小要求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存分配给请求者,余下的空闲分区仍留在空闲分区链 中。
优点: 该算法倾向于使用内存中低地址部分的空闲区,在高地址部分的空闲区很少被利用,从而保留了高地址部分的大空闲区。显然为以后到达的大作业分配大的内存空间创造了条件。
缺点:低地址部分不断被划分,留下许多难以利用、很小的空闲区,而每次查找又都从低地址部分开始,会增加查找的开销。
二、最佳适应算法:该算法总是把既能满足要求,又是最小的空闲分区分配给作业。为了加速查找,该算法要求将所有的空闲区按其大小排序后,以递增顺序形成一个空白链。这样每次找到的第一个满足要求的空闲区,必然是最优的。孤立地看,该算法似乎是最优的,但事实上并不一定。因为每次分配后剩余的空间一定是最小的,在存储器中将留下许多难以利用的小空闲区。同时每次分配后必须重新排序,这也带来了一定的开销。
优点:每次分配给文件的都是最合适该文件大小的分区。
缺点:内存中留下许多难以利用的小的空闲区。
三、最坏适应算法:最坏适应算法是将输入的作业放置到主存中与它所需大小差距最大的空闲区中。空闲区大小由大到小排序。
优点:尽可能地利用存储器中大的空闲区。
缺点:绝大多数时候都会造成资源的严重浪费甚至是完全无法实现分配。
本次实验加深了我对于动态空间分配的理解,为之后更好理解操作系统提供了帮助。
占坑
已收藏,马上要交大作业了,芜湖起飞!
标题什么的稍微改下名字,别用重了2333