【操作系统原理】页面置换算法模拟

完整代码包传送门

Page displacement algorithm simulation

相关文章

【操作系统原理】信号量的应用

【操作系统原理】进程的管道通信

【操作系统原理】Linux多线程的创建和控制

【操作系统原理】进程调度模拟

【操作系统原理】进程创建与控制

原理与内容

1、 请求分页虚拟内存管理
请求分页虚拟内存管理是建立在基本分页基础上的,为了能支持虚拟存储器功能,而增加了请求调页功能和置换功能。
2、工作集
多数程序都显示出高度的局部性,也就是说,在一个时间段内,一组页面被反复引用。这组被反复引用的页面随着时间的推移,其成员也会发生变化。有时这种变化是剧烈的,有时这种变化则是渐进的。我们把这组页面的集合称为工作集
3、缺页率
缺页中断次数/总的页面访问次数

4、算法介绍

(1)先进先出置换算法
先进先出置换算法的主要思想是,在发生页面替换时,被替换的对象应该是最早进入内存的。

(2)最近最久未使用置换算法
最近最久未使用置换算法的主要思想是,在发生页面替换时,被替换的页面应该满足,在之前的访问队列中,该对象截止目前未被访问的时间最长。

(3)Clock置换算法

设置访问位,设置指向系统中最老的页面,每次从最老的页面开始查找,若访问位为1,则将访问位清零,指针向后移,直到找到访问位为0的页面淘汰。

(4)改进型Clock置换算法
改进型Clock置换算法的主要思想是,在Clock算法基础上,增加修改位,在每次页面替换时,总是尽可能地先替换掉既未被访问又未被修改的页面。

过程与结果

一、先进先出页面置换算法(FIFO)实现

FIFO的算法思想是总是淘汰最先进入内存的页面,即选择在内存驻留时间最长的页面予以淘汰,我们可以借助优先队列来简单的实现。

其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将最先进入内存的页面进行置换。

【操作系统原理】页面置换算法模拟_第1张图片

首先引入队列的库,定义3个物理块,n、m分别为总的页面访问次数与缺页中断次数,创建优先队列对象,容量为3并进行初始化。

进行替换更新页面操作,循环输入输出,代码如下:

【操作系统原理】页面置换算法模拟_第2张图片

进行输入输出样例:

【操作系统原理】页面置换算法模拟_第3张图片

可以看到缺页中断率为9/12 = 0.75%

核心代码如下:

while(k != -1):
    n += 1
    if k not in frame: # 缺页
        m += 1
        old_k = queue_obj.get() # 被替换的页面
        frame[frame.index(old_k)] = k # 更新物理块
        
        queue_obj.put(k)# 更新优先队列
        print("发生更新,更新后页面:",frame)
        print("被替换的页面:",old_k)
    else:
        print("发生命中,当前页面:",frame)

    k = int(input("请输入要访问的页号,终止输入:-1:"))

二、最近最久未使用(LRU)实现

LRU的算法思想是选择最近一段时间最久未使用的页面予以淘汰。其算法的特点是:考虑了程序设计的局部性原理,有一定合理性,但页面的过去和未来走向无必然联系;需要跟踪记录每一页的使用情况,系统开销较大。

其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将选择最近一段时间最久未使用的页面予以淘汰(即将内存里的页号一一去判断其前最近在序列中的使用序号,序号最小者予以淘汰)。

一般来说LRU可以看作维护一个栈排序的过程,这里使用字典比较方便逻辑理解。替换的权重是时间度,依据时间度进行页面的更新输出,代码截图如下:

【操作系统原理】页面置换算法模拟_第4张图片

同样进行输入输出样例:

【操作系统原理】页面置换算法模拟_第5张图片

可以看到缺页中断率稍有优化,为10/12 = 0.83%

核心代码如下:

while(int(k) != -1):
    n += 1
    if len(lru) < 3:
        m += 1
        lru[k] = 0
        frame.append(k)
        print("发生更新,更新后页面:",frame)

    else:
        if k not in frame: # 缺页
            m += 1
            old_k = max(lru, key = lru.get) # 被替换的页面是时间度最多的的
            frame[frame.index(old_k)] = k # 更新物理块
            del lru[old_k]
            lru[k] = 0 # 更新页面,时间度初始化为零

            # print(lru)
            print("发生更新,更新后页面:",frame)
            print("被替换的页面:",old_k)
        else:
            print("发生命中,当前页面:",frame)
            for key,value in lru.items():
                if key == k: # 发生命中,即命中的时间度重置,非命中的时间度加一
                    lru[key] = 0
                else: lru[key] = value + 1
            # print(lru)

三、简单CLOCK置换算法

简单CLOCK置换算法的算法思想是 (1)为每页设置一位访问位,再将内存中所有页面通过链接指针链成一个循环队列。(2)当某页被访问时,其访问位被置1,表示该页最近使用过。(3)置换算法在选择一页淘汰时,只需循环检查各页的访问位:如果为1,则将该访问位置0,暂不换出;如果为0,则将该页换出,算法终止。

其算法实现过程:当有新的访问页面要进入时,首先判断内存容量是否为满,如果不满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,如果不在,则将该页直接调入内存,同时将其访问位置1,同时指针指向修改位的下一位。如果内存已满,再判断所要访问的页面是否在内存中,如果在,则命中输出,不需要将该页调入内存,同时将其访问位置1。如果不在,则从指针开始依次进行循环判断,若访问位为1则跳过,同时将其置0,若访问位为0,则进行置换,同时将其访问位置0。

以输出和对索引值index的除余处理模拟循环队列的实现,进行物理块、记录位、指针的定义及初始化

【操作系统原理】页面置换算法模拟_第6张图片

简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描

【操作系统原理】页面置换算法模拟_第7张图片

同样进行输入输出样例:

【操作系统原理】页面置换算法模拟_第8张图片

可以看到缺页中断率稍有优化,为9/12 = 0.75%

核心代码如下:

while(int(k) != -1):
    n += 1
    if k not in frame:
        tt = 0
        m += 1
        for i in range(len(frame)): # 第一轮查找
            if clock[index] == 1: 
                clock[index] = 0
                index = (index + 1) % 3
            elif clock[index] == 0: # 找到
                old_k = frame[index]
                frame[index] = k
                clock[index] = 1
                tt = 1
                index = (index + 1) % 3
                break
                

        if tt != 1: # 第一轮没有找到,查找第二轮
            for i in range(len(frame)):
                if clock[index] == 0: 
                    old_k = frame[index]
                    frame[index] = k
                    clock[index] = 1
                    index = (index + 1) % 3
                    break
                    
                    
        # print(clock)
        print("发生更新,更新后页面:",frame)
        print("被替换的页面:",old_k)

    else:
        print("发生命中,当前页面:",frame)
        t = frame.index(k)
        clock[t] = 1 # 发生命中,标志位重置为1
        # index = (index + 1) % 3 
        # print(clock)

四、改进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页面进行置换。

和简单Clock算法不同的是增加了修改位的定义及初始化

【操作系统原理】页面置换算法模拟_第9张图片

分为三轮进行搜索:

【操作系统原理】页面置换算法模拟_第10张图片

使用相同页面访问序列进行输入输出样例:

【操作系统原理】页面置换算法模拟_第11张图片

可以看到缺页中断率为10/12 = 0.83%

核心代码如下:

while(int(k) != -1):
    n += 1
    if k not in frame: # 缺页,简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)
        tt = 0
        m += 1
        for i in range(len(frame)): # 第一轮查找
            if clock[index] == 0 and update[index] == 0: 
                old_k = frame[index]
                frame[index] = k
                clock[index] = 1
                update[index] = 1
                tt = 1
                index = (index + 1) % 3
                break
                
        if tt != 1: # 第一轮没有找到,查找第二轮
            for i in range(len(frame)):
                if clock[index] == 0 and update[index] == 1:
                    old_k = frame[index]
                    frame[index] = k
                    clock[index] = 1
                    update[index] = 1
                    index = (index + 1) % 3
                    tt = 1
                    break
                clock[i] = 0 # 将所有扫描过的页面的访问位置0
        if tt != 1: # 第二轮没有找到,查找最后一轮
            if clock[index] == 0 and update[index] == 0: 
                old_k = frame[index]
                frame[index] = k
                clock[index] = 1
                update[index] = 1
                tt = 1
                index = (index + 1) % 3
                break
                    
        # print(clock)
        print("发生更新,更新后页面:",frame)
        print("被替换的页面:",old_k)

    else:
        print("发生命中,当前页面:",frame)
        t = frame.index(k)
        clock[t] = 1 # 发生命中,标志位重置为1
        update[t] = 1
        # index = (index + 1) % 3 
        # print(clock)

你可能感兴趣的:(操作系统原理,python)