zoukankan      html  css  js  c++  java
  • 模拟请求分页式存储管理 ---4种置换算法

    请求调页+页面置换

    1.虚拟存储系统

    操作系统中,为了提高内存利用率,提供了内外存进程对换机制;内存空间的分配和回收均以页为单位进行;一个进程只需将其一部分(段或页)调入内存便可运行;还支持请求调页的存储管理方式。

    当进程在运行中需要访问某部分程序和数据时,发现其所在页面不在内存,就立即提出请求(向CPU发出缺中断),由系统将其所需页面调入内存。这种页面调入方式叫请求调页。

     

    2. 页面置换过程

    当CPU接收到缺页中断信号,中断处理程序先保存现场,分析中断原因,转入缺页中断处理程序。该程序通过查找页表,得到该页所在外存的物理块号。如果此时内存未满,能容纳新页,则启动磁盘I/O将所缺之页调入内存,然后修改页表。如果内存已满,则须按某种置换算法从内存中选出一页准备换出,是否重新写盘由页表的修改位决定,然后将缺页调入,修改页表。利用修改后的页表,去形成所要访问数据的物理地址,再去访问内存数据。整个页面的调入过程对用户是透明的。

     

    (1)   页表:放在系统空间的页表区,存放逻辑页与物理页帧的对应关系。 每一个进程都拥有一个自己的页表,PCB表中有指针指向页表。

    (2)   页框:RAM块,来描述物理内存空间,由操作系统实现从逻辑页到物理页框的页面映射,同时负责对所有页的管理和进程运行的控制。模拟时对于页框的分配数量自主设定。

    (3)   访问位:不论是读还是写(get or set),系统都会设置该页的访问位,记录本页在一段时间内被访问的次数,或最近已有多长时间未被访问,它的值用来帮助操作系统在发生缺页中断时选择要被淘汰的页,即用于页面置换。

    (4)   修改位(脏位):用于页面的换出,如果某个页面被修改过(即为脏),在淘汰该页时,必须将其写回磁盘,反之,可以直接丢弃该页。

    (5) 有效位(驻留位、中断位):表示该页是内存还是磁盘。

    (6) 保护位:存取控制位,用于指出该页允许什么类型的访问,如果用一位来标识的话:1表示只读,0表示读写。

     

    1.LRU

    least recently used 最近时间内 最久未被使用的页面被置换

    如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小,拿“最近的过去”预测“最近的未来”。

    LRU算法的硬件支持

    LRU算法虽然是一种比较好的算法,但是要求系统有较多的支持硬件。为了了解一个进程在内存中的各个页面各有多少时间未被进程访问,以及如何快速得知道哪一页是最近最久未使用的页面,须有寄存器和栈两类硬件之一的支持。 
    1)寄存器 
    为了记录某进程在内存中各页的使用情况,须为每个内存中的页面配置一个移位寄存器,可表示为 

    R=Rn1Rn2R2R1R0


    当进程访问某物理块时,要将相应的寄存器的Rn1位置成1。此时,定时信号将每隔一定时间将寄存器右移一位。如果我们把n位寄存器的数看作是一个整数,那么,具有最小数值的寄存器所对应的页面,就是最近最久未使用的页面。 (e.g. 每100ms右移一位,最高位补0还是补1的问题)
    2)栈 
    可利用一个特殊的栈保持当前使用的各个页面的页面号。每当进程访问某页面是,便将该页面的页面号从栈中移出,将它压入栈顶。因此,栈顶始终是最近最久未使用页面的页面号。

    模拟实现2:

    采用双向链表+heapmap配合实现,靠近链表头部的越是最近访问过得,链表尾部是最久未被访问的,从而体现使用的时间顺序,heapmap记录表项地址。

    过程:

    要操作页面K

           未在内存 1.内存未满->直接插入链表头部,记录地址

                           2.内存已满->先删除链表尾部节点,再插入新节点到链表头部,并且更新map中增加该节点

           已在内存:更新节点的值,把当前访问的节点移到链表头部,并且更新map中该节点的地址。

    class LRUBlock{
    public:
        LRUBlock(int capacity) {
            size = capacity;
        }
    
        /**
            操作页面k
        */
        void set(int blockId,int k) {
            ///未在内存
            if(blockMap.find(k) == blockMap.end())
            {
                if(blockList.size() == size)
                {///删除链表尾部节点(最少访问的节点)
                    blockMap.erase(blockList.back().pageId);
                    blockList.pop_back();
                }
                ///插入新节点到链表头部,并且更新map中增加该节点
                blockList.push_front(BlockNode(blockId,k));
                blockMap[k] = blockList.begin();
            }
            ///已在内存
            else
            {
                ///更新节点的值,把当前访问的节点移到链表头部,并且更新map中该节点的地址
                blockList.splice(blockList.begin(), blockList, blockMap[k]);
                blockMap[k] = blockList.begin();
            }
        }
        list<BlockNode> getList()
        {
            return this->blockList;
        }
    private:
        list<BlockNode> blockList;
        unordered_map<int, list<BlockNode>::iterator> blockMap;///记录结点地址
        int size;
    };
    void LRU(LRUBlock&lru,int address,map<int,TableEntry>&pageTable,map<int,int>&memoryBlock)
    {
        int pageNum=address/unitBlockSize;
        if(pageTable[pageNum].entryStatus==1){
            cout<<"页面已在内存中
    ";
            lru.set(pageTable[pageNum].blockId,pageNum);
        }
        else
        {
            int s=memoryBlock.size();
            if(memoryBlock[s-1]==1){///直接分
                cout<<"所分配内存块还未用完
    ";
                int i=s-1;
                for(;i>=0;i--){
                    if(memoryBlock[i]==0)break;
                }
                memoryBlock[i+1]=0;
                pageTable[pageNum].entryStatus=1;
                pageTable[pageNum].blockId=i+1;
                lru.set(i+1,pageNum);
            }
            else///先swap再分
            {
                cout<<"所分配内存块全被占用,需要置换操作
    ";
                BlockNode blockNode=lru.getList().back();
                cout<<"置换出"<<blockNode.pageId<<"	置换入"<<pageNum<<endl;
                ///
                pageTable[blockNode.pageId].entryStatus=0;
                pageTable[blockNode.pageId].blockId=-1;
    
                pageTable[pageNum].entryStatus=1;
                pageTable[pageNum].blockId=blockNode.blockId;
    
                lru.set(blockNode.blockId,pageNum);
            }
            pageBreak++;
        }
        total++;
    }

    2.LFU:

    least frequently used 最少使用置换

    如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小,LRU的淘汰规则是基于访问时间,而LFU是基于访问次数的。

    注意:

    一般情况下,LFU效率要优于LRU,且能够避免周期性或者偶发性的操作导致缓存命中率下降的问题。但LFU需要记录数据的历史访问记录,一旦数据访问模式改变,LFU需要更长时间来适用新的访问模式,即:LFU存在历史数据影响将来数据的“缓存污染”效用。

    实现:

    用数组存储内存中表项情况,通过遍历查找最小值。

    过程:

    要操作页面K

           未在内存 1.内存未满:更新页表,表项放入数组。

                           2.内存已满:更新页表,数组删除要淘汰的表项,加入新表项。

           已在内存:更新页表,表项重新放入数组。

    3.FIFO

    first in first out 最早出现置换

    队列实现

    过程:

    已在内存:none

    不在内存:

      内存未满:表项加入队尾

      内存已满:pop队首,新表项加入队尾

    4.CLOCK

    NRU---Not Recently Used

    用数组存储内存中表项情况,修改数组中表项访问情况选择置出页面。

    置换策略:依次访问数组中的表项,遇到status=1的置为0,再给一次驻留内存的机会,遇到status=0的换出。

    过程:

    已在内存:none

    不在内存:

      内存未满:表项加入数组

      内存已满:拿新来表项替换置出表项

     

     

     

  • 相关阅读:
    几个常用myeclipse快捷键
    5G layer
    customize the entry point of pod runtime
    关于JS Pormise的认识
    修改 /etc/pam.d/login, linux 本地账号密码无法登陆,一直返回 登陆的login界面
    Java支付宝PC网站支付功能开发(详细教程)
    支付宝PC支付功能异步通知签名验证失败解决方案
    提交代码出现 Push to origin/master was rejected 错误解决方法
    易语言连接RCON详细教程实例(演示连接Unturned服务器RCON)
    易语言调用外部DLL详细实例教程
  • 原文地址:https://www.cnblogs.com/kimsimple/p/7065929.html
Copyright © 2011-2022 走看看