利用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+1if 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的缺页率在物理块一样时相近。

相应的word版文档和完整代码,可以查看链接: link. 原创不易,生活所迫!!!若有积分的也可以点击文尾的链接,积分下载(里面是PDF版以及完整代码),或者留下你的邮箱,但我比较忙,所以回的可能会比较慢。

由于篇幅原因,后面对于过程和关系研究代码在此不进行粘贴,我将所有的代码以及报告文档打包为一个压缩包,请点击
请求分页管理压缩包链接.

温馨提示:有任何问题,可以在留言区留言,我会回答大家的问题,觉得对你有帮助的,可以关注一下,我会定期更新博客,内容很广。

评论 78
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

创创大帝(水印很浅-下载的文档)

原创不易,小钱也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值