利用python实现OPT、FIFO、LRU、LFU、简单的和改进的CLOCK共六种页面置换算法,并对六种算法的过程和关系进行分析(操作系统课程设计)
特别声明:本博客属于原创内容,若需转载或引用,请均注明转载和加上相应的链接信息!!!!
设计目的
为了研究缺页率与物理块数、随机性之间的关系,同时将页面置换算法的置换过程进行动态呈现出来。在实际进程运行过程中,若其所要访问的页面不在内存,而需把她们呢调入内存,但内存已无空闲空间时,为了保证该进程能够正常运行,系统必须从内存中调出一页程序或数据送到磁盘的对换区,这时就需要合适的页面置换算法进行工作,置换算法的好坏将直接影响到系统的性能,不适当的算法可能会导致进程发生“抖动”。
设计内容
(1)请根据理论教材所授内容,采用自己熟悉的编程语言模拟实现OPT、FIFO、LRU、LFU、简单的和改进的CLOCK共六种页面置换算法。
(2)要求:(a) 各置换算法所请求的页面序列是随机产生的,而不是人为输入,在执行时应只需改变页面序列的大小就可以得到不同的页面序列,其中随机性通过一定的参数进行控制而且这些参数要便于调整。(b) 对每一算法,程序依次测试物理块数(内存容量)为2、3、4、5、6、7、8七种情况下的缺页率和置换率,并能自动统计分析出各算法缺页率与物理块、随机性之间的关系(要求程序最终能生成性能曲线图)。© 程序应能动态显示各算法的具体置换过程。
总体设计
开发环境
本设计使用的开发环境为Python3.6+window10,在eclipse上进行编译运行,运用了matplotlib、numpy、random三个库。
算法设计
本次设计中共利用Python实现了OPT、FIFO、LRU、LFU、简单和改进的CLOCK六种页面置换算法。
3.1 最佳置换算法(OPT)
介绍:
OPT的算法思想是选择以后永不使用的或是在(未来)最长时间内不再被访问的页面作为淘汰页面置换出去。其特点是理想化算法,具有最好的性能,可使缺页率最低,但在实际应用中难以确定理想的淘汰页面,因此算法难以实现。
其算法的实现过程为:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则判断在内存中的页号谁在未来最长时间不被访问(即判断各页号在未来时间里最早出来再次访问的序号最大的,假如不在被访问,则设序号为无限大)予以置换。
代码:
#作者:余创 def OPT(link,num1): #定义OPT算法函数 传入内存容量num1,工作的随机序列link print(" 使用OPT置换算法:") links=[-1 for i in range (num1)] #初始化内存序列 a1=0 # 初始化参数 max=0 # 初始化参数 give=0 # 初始化参数 error_OPT=0 # 初始化需要缺页次数 rate_OPT=0 #初始化缺页率 for i in range(len(link)): #循环工作的随机序列 print(i,end=" ") if (give<num1): for j in range(num1): if(links[j]==link[i]): #判断是否命中 print("命中!") break else: if (links[j]<0): links[j]=link[i] #将缺失页面加入内存 error_OPT=error_OPT+1 #缺页数加1 give=give+1 print(links) break else: continue elif(give==num1): #判断内存是否满 if(link[i] in links): print("命中!") continue else: for j in range(num1): if links[j] not in link[i+1 : len(link)]: #判断访问页面是否在内存 a1=j break else: for k in range(i+1,len(link)): #循环从当前到工作序列末 if link[k]==links[j]: if k>max: max=k #记录最远使用页面序号 a1=j break else: break for m in range(a1,num1-1): links[m]=links[m+1] links[num1-1]=link[i] error_OPT=error_OPT+1 print(links) rate_OPT=error_OPT/len(link) rate_OPT_arr.append(rate_OPT) #将缺页率加到rate_OPT_arr数组中 print(" 当请求页面序列长度为{0},内存容量为{1},OPT缺页率为{2}" .format(len(link),num1,error_OPT/len(link))) print(" 当请求页面序列长度为{0},内存容量为{1},OPT置换率为{2}" .format(len(link),num1,(error_OPT-num1)/len(link)))
3.2先进先出页面置换算法(FIFO)
介绍:
FIFO的算法思想是总是淘汰最先进入内存的页面,即选择在内存驻留时间最长的页面予以淘汰 。其算法特点简单、易实现;貌似公平,实际上不公平,不切实际,有些经常被访问的页面可能先被淘汰,因此性能较差。
其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将最先进入内存的页面进行置换。
代码:(部分代码注释同OPT)
#作者:余创 def FIFO(link,num1): print(" 使用FIFO置换算法:") links=[-1 for i in range (num1)] give=0 error_FIFO=0 rate_FIFO=0 for i in range(len(link)): print(i,end=" ") if (give<num1): for j in range(num1): if(links[j]==link[i]): print("命中!") break else: if (links[j]<0): links[j]=link[i] print(links) error_FIFO=error_FIFO+1 give=give+1 break else: continue elif(give==num1): if(link[i] in links): print("命中!") continue else: for k in range(num1-1): links[k]=links[k+1] #将队首的页面置换掉 links[num1-1]=link[i] #将置换的页面放在队尾 error_FIFO=error_FIFO+1 print(links) rate_FIFO=error_FIFO/len(link) rate_FIFO_arr.append(rate_FIFO) print(" 当请求页面序列长度为{0},内存容量为{1},FIFO缺页率为{2}" .format(len(link),num1,error_FIFO/len(link))) print(" 当请求页面序列长度为{0},内存容量为{1},FIFO置换率为{2}" .format(len(link),num1,(error_FIFO-num1)/len(link)))
3.3 最近最久未使用(LRU)
介绍:
LRU的算法思想是选择最近一段时间最久未使用的页面予以淘汰。其算法的特点是:考虑了程序设计的局部性原理,有一定合理性,但页面的过去和未来走向无必然联系;需要跟踪记录每一页的使用情况,系统开销较大。
其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将选择最近一段时间最久未使用的页面予以淘汰(即将内存里的页号一一去判断其前最近在序列中的使用序号,序号最小者予以淘汰)。
代码:(部分代码注释同OPT)
#作者:余创 def LRU(link,num1): print(" 使用LRU置换算法:") links=[-1 for i in range (num1)] a1=0 give=0 error_LRU=0 rate_LRU=0 for i in range(len(link)): min=5000000000 print(i,end=" ") if (give<num1): for j in range(num1): if(links[j]==link[i]): print("命中!") break else: if (links[j]<0): links[j]=link[i] print(links) error_LRU=error_LRU+1 give=give+1 break else: continue elif(give==num1): if(link[i] in links): print("命中!") continue else: for j in range(num1): for k in range(i-1,-1,-1): #遍历工作序列当前位置到序列头 if link[k]==links[j]: if k<min: min=k #记录内存中页号最早出现且序号最小予以置换 a1=j break else: break for m in range(a1,num1-1): links[m]=links[m+1] links[num1-1]=link[i] error_LRU=error_LRU+1 print(links) rate_LRU=error_LRU/len(link) rate_LRU_arr.append(rate_LRU) print(" 当请求页面序列长度为{0},内存容量为{1},LRU缺页率为{2}" .format(len(link),num1,error_LRU/len(link))) print(" 当请求页面序列长度为{0},内存容量为{1},LRU置换率为{2}" .format(len(link),num1,(error_LRU-num1)/len(link)))
3.4 最少使用置换算法(LFU)
介绍:
LFU的算法思想是与LRU类似,设置一个移位寄存器记录页面访问情况,如要置换页面,选择∑Ri值最小的页面进行淘汰。其特点是:实现比较简单但并不能真正反映页面的使用情况。
其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将截止现在使用次数最少的页面进行置换,若相同则将最近的进行置换(即对内存中的每个页面依次判断他在使用序列里使用的次数,次数最小的予以淘汰)。
代码:部分代码注释同OPT)
作者:余创 def LFU(link,num1): print(" 使用LFU置换算法:") links=[-1 for i in range (num1)] a1=0 give=0 error_LFU=0 rate_LRU=0 for i in range(len(link)): min=5000000000 min2=5000000000 print(i,end=" ") if (give<num1): for j in range(num1): if(links[j]==link[i]): print("命中!") break else: if (links[j]<0): links[j]=link[i] print(links) error_LFU give=give+1 break else: continue elif(give==num1): if(link[i] in links): print("命中!") continue else: for j in range(num1): a2=0 for k in range(0,i): #遍历工作序列当前位置到序列头 if link[k]==links[j]: a2=a2+1 else: continue if min>a2: #寻找使用次数最少的页面 min=a2 min2=k a1=j elif(min==a2): #若相等则找序号最小的 if min2>k: min2=k a1=j for m in range(a1,num1-1): links[m]=links[m+1] links[num1-1]=link[i] error_LFU=error_LFU+1 print(links) rate_LFU=error_LFU/len(link) rate_LFU_arr.append(rate_LFU) print(" 当请求页面序列长度为{0},内存容量为{1},LFU缺页率为{2}" .format(len(link),num1,error_LFU/len(link))) print(" 当请求页面序列长度为{0},内存容量为{1},LFU置换率为{2}" .format(len(link),num1,(error_LFU-num1)/len(link)))
3.5 简单CLOCK置换算法
介绍:
简单CLOCK置换算法的算法思想是 (1)为每页设置一位访问位,再将内存中所有页面通过链接指针链成一个循环队列。(2)当某页被访问时,其访问位被置1,表示该页最近使用过。(3)置换算法在选择一页淘汰时,只需循环检查各页的访问位:如果为1,则将该访问位置0,暂不换出;如果为0,则将该页换出,算法终止。
其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存,同时将其访问位置1,同时指针指向修改位的下一位。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,同时将其访问位置1。如果不在,则从指针开始依次进行循环判断,若访问位为1则跳过,同时将其置0,若访问位为0,则进行置换,同时将其访问位置0。
代码:部分代码注释同OPT)
#作者:余创 def BASIC_CLOCK(link,num1): print(" 使用BASIC_CLOCK置换算法:") links=[-1 for i in range (num1)] give=0 link1=[0 for i in range (num1)] #初始化化访问位 a1=0 a2=0 error_BASIC_CLOCK=0 rate_BASIC_CLOCK=0 for i in range(len(link)): print(i,end=" ") if (give<num1): for j in range(num1): if(links[j]==link[i]): print("命中!") break else: if (links[j]<0): links[j]=link[i] link1[j]=1 #序列对应访问位置1 print(links) error_BASIC_CLOCK=error_BASIC_CLOCK+1 give=give+1 a2=a2+1 break else: continue elif(give==num1): for j in range(num1): if(link[i] in links): if (links[j]==link[i]): link1[j]=1 #序列对应访问位置1 print("命中!") break else: continue else: for k in range((a2 % num1),(a2 % num1)+num1+1): #循环遍历num1+1次 if link1[k%num1]==0: #判断访问位是否为0 links[k%num1]=link[i] error_BASIC_CLOCK=error_BASIC_CLOCK+1 print(links) a2=k+1 link1[k%num1]=1 break else: link1[k%num1]=0 break rate_BASIC_CLOCK=error_BASIC_CLOCK/len(link) rate_BASIC_CLOCK_arr.append(rate_BASIC_CLOCK) print(" 当请求页面序列长度为{0},内存容量为{1},BASIC_CLOCK缺页率为{2}" .format(len(link),num1,error_BASIC_CLOCK/len(link))) print(" 当请求页面序列长度为{0},内存容量为{1},BASIC_CLOCK置换率为{2}" .format(len(link),num1,(error_BASIC_CLOCK-num1)/len(link)))
3.6 改进CLOCK置换算法
介绍:
改进CLOCK置换算法的算法思想是 改进型Clock算法每次选择的淘汰页面除了最近未被使用过,最好还未被修改过(使置换代价尽可能小)。每页设置一个访问位A和一个修改位M。算法步骤第1步(第1轮扫描):寻找第一类页面,将所遇到的第1个第一类页面作为淘汰页面,如果找不到,则转入第2步。第2步(第2轮扫描):寻找第二类页面,将所遇到的第1个第二类页面作为淘汰页面,如果找不到,则转入第3步。在扫描期间,将所有扫描过的页面访问位置0。第3步:将指针返回到开始的位置,转第1步。算法特点:减少了磁盘I/O次数;但可能要经过多轮扫描
表3-1 改进CLOCK置换算法页的种类
第一类页面 A=0 M=0 最佳淘汰页面
第二类页面 A=0 M=1 次佳淘汰页面
第三类页面 A=1 M=0 该页可能再被访问
第四类页面 A=1 M=1 该页可能再被访问
其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,同时将访问位置1,修改位置1。如果不在,则将该页直接调入内存,同时将其访问位置1,修改位置0,同时指针指向修改位的下一位。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,同时将其访问位置1,修改位置1。如果不在,则从指针开始依次进行循环判断,寻找A=0,M=0页面,将所遇到的第1此页面作为淘汰页面。如果找不到,则循环寻找A=0,M=1页面,在循环扫描期间,将所有扫描过的页面的访问位置0。若在一个循环内也没找到A=0,M=1页面,由于扫描过的页面的访问位置0,所以再进行寻找是否有A=0,M=0页面,若没有则必然有A=0,M=1页面进行置换。
代码:部分代码注释同OPT)
#作者:余创 def IMPROVE_CLOCK(link,num1): print(" 使用IMPROVE_CLOCK置换算法:") links=[-1 for i in range (num1)] give=0 link1=[0 for i in range (num1)] #初始化访问位序列 link2=[1 for i in range (num1)] #初始化修改位序列 a1=0 a2=0 error_IMPROVE_CLOCK=0 rate_IMPROVE_CLOCK=0 for i in range(len(link)): print(i,end=" ") if (give<num1): for j in range(num1): if(links[j]==link[i]): print("命中!") link1[j]=1 #访问位置1 link2[j]=1 #修改位置1 break else: if (links[j]<0): links[j]=link[i] error_IMPROVE_CLOCK=error_IMPROVE_CLOCK+1 link1[j]=1 link2[j]=0 print(links) give=give+1 a2=a2+1 break else: continue elif(give==num1): for j in range(num1): m=0 if(link[i] in links): if (links[j]==link[i]): link1[j]=1 link2[j]=1 print("命中!") break else: continue else: for k in range((a2 % num1),(a2 % num1)+num1): if (link1[k%num1]==0) & (link2[k%num1]==0):#判断是否为第一类页面 links[k%num1]=link[i] error_IMPROVE_CLOCK=error_IMPROVE_CLOCK+1 print(links) a2=k+1 link1[k%num1]=1 link2[k%num1]=0 m=m+1 break else: m=m+1 continue if(m==num1): for k in range((a2 % num1),(a2 % num1)+num1): if (link1[k%num1]==0) & (link2[k%num1]==1):#判断是否为第二类页面 links[k%num1]=link[i] error_IMPROVE_CLOCK=error_IMPROVE_CLOCK+1 print(links) a2=k+1 link1[k%num1]=1 link2[k%num1]=0 break else: m=m+1 link1[k%num1]=0 #将所扫描到的循环页面访问位置0 if(m==2*num1): for k in range((a2 % num1),(a2 % num1)+num1): if (link1[k%num1]==0) & (link2[k%num1]==0): links[k%num1]=link[i] error_IMPROVE_CLOCK=error_IMPROVE_CLOCK+1 print(links) a2=k+1 link1[k%num1]=1 link2[k%num1]=0 break else: m=m+1 continue if(m==3*num1): for k in range((a2 % num1),(a2 % num1)+num1): if (link1[k%num1]==0) & (link2[k%num1]==1): links[k%num1]=link[i] error_IMPROVE_CLOCK=error_IMPROVE_CLOCK+1 print(links) a2=k+1 link1[k%num1]=1 link2[k%num1]=0 break break rate_IMPROVE_CLOCK=error_IMPROVE_CLOCK/len(link) rate_IMPROVE_CLOCK_arr.append(rate_IMPROVE_CLOCK) print(" 当请求页面序列长度为{0},内存容量为{1},IMPROVE_CLOCK缺页率为{2}" .format(len(link),num1,error_IMPROVE_CLOCK/len(link))) print(" 当请求页面序列长度为{0},内存容量为{1},IMPROVE_CLOCK置换率为{2}" .format(len(link),num1,(error_IMPROVE_CLOCK-num1)/len(link)))
观察缺页率和置换率
除了编写算法以外,还实现了对缺页率和置换率的观察(下图只是一部分)
显示置换过程
除了编写算法以外,还实现了显示置换过程(下图只是一部分)
缺页率与随机性之间关系
除了编写算法以外,还实现了对缺页率与随机性之间关系的探究
由图像观察可得虽然页面序列的随机性可以影响缺页率,但是影响的程度并不非常大,其相差在0.1以内。
缺页率与物理块数之间关系
除了编写算法以外,还实现了缺页率与物理块数之间关系的探究
由图像观察可得:缺页率随着物理块的增加明显减小。同时可以看出OPT页面置换算法的缺页率明显小于其他五种算法,FIFO、LRU、LFU、简单和改进的CLOCK的缺页率在物理块一样时相近。
由于篇幅原因,后面对于过程和关系研究代码在此不进行粘贴,我将所有的代码以及报告文档打包为一个压缩包,请点击
请求分页管理压缩包链接.
温馨提示:有任何问题,可以在留言区留言,我会回答大家的问题,觉得对你有帮助的,可以关注一下,我会定期更新博客,内容很广。
- 转载:操作系统页面置换算法(opt,lru,fifo,clock)实现
- opt, lru, fifo, lfu等页面置换算法的python实现
- [python]实现操作系统虚拟内存中的页替换算法FIFO,OPT,LRU
- C#实现页面置换算法FIFO,LRU,LFU,OPT
- 使用C++STL中的deque实现操作系统FIFO、LRU页面置换算法
- 操作系统虚拟内存中的四种典型页替换算法(OPT,LRU,FIFO,Clock)
- 利用 Python 进行数据分析(一)简单介绍
- 利用Abaqus的Python脚本实现进行自动分析的方法
- 利用 Python 进行数据分析(七)pandas 简单介绍(Series 和 DataFrame)
- JAVA实现页面置换算法(OPT,FIFO,LRU)
- 操作系统虚拟内存中的四种典型页替换算法(OPT,LRU,FIFO,Clock)
- AdaBoost中利用Haar特征进行人脸识别算法分析与总结2——级联分类器与检测过程
- Python - 操作系统FIFO、LRU算法缺页率计算
- 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍
- 利用python实现对分类变量与数值变量混合的数据进行聚类分析
- 利用Python_keras编写简单BP神经网络以及初步分析的算法
- 线性时间选择 python实现 计算机算法设计与分析
- AdaBoost中利用Haar特征进行人脸识别算法分析与总结2——级联分类器与检测过程 .
- 操作系统虚拟内存中的四种典型页替换算法(OPT,LRU,FIFO,Clock)
- 简单的java缓存实现(LRU,LFU,FIFO)