操作系统总结(九)虚拟内存

利用虚拟内存,可以编写大于实际内存的程序;采用部分程序加载到内存中,可以同时执行更多的进程,并发度好,效率高。将需要的部分放入内存,有些用不到的部分从来不放入内存,内存利用率高 ,程序开始执行、响应时间等更快。使用虚拟内存有利于系统,同时也有利于用户。

 虚拟内存的实现

早期:内存不足时以进程为单位在内外存之间交换;现在:按需调页(调页,也称惰性交换,以页为单位在内外存 之间交换,即对不在内存中的“页”,当进程执行时要用时才调入,否则不调入)。

虚拟内存实现中,部分线性地址对应物理页,其他对应磁盘相应位置。为了记录页是否在内存中,我们需要改造页表,在页表项中添加有效/无效的标志位(v/i),在请求调页的过程中,当访问没有映射的线性地址时,会出发页错误处理程序,页错误处理程序将访问对应的磁盘内容,将其取出放入到内存中,然后重新访问。尽管为了保证效率,分配给一个进程的物理框好应足够多,但是根据程序的局部性原理,页面4k当调入一个页面时,很多程序不会出错。

具体实现细节如下

  1. load[addr]->没有映射到物理内存(根据addr查表(MMU),查询标志位,引发缺页中断)
  2. 设置缺页中断
  3. 缺页中断处理程序读取磁盘得到需要的页
  4. 选择一个空的页框,写入
  5. 修改页表
  6. 重新开始指令

如何重新开始指令:需要硬件支持,jmp到上一条指令的地址即可

如何选取空闲的页框

空闲的页框是有限的,如果用完了需要进行页框的淘汰,有很多的淘汰机制。我们可以用缺页次数评价淘汰算法。

  1. FIFO

    即先入先出原则,如果淘汰的就是下一个要用的呢?无法预测

  2. OPT(MIN)

    选择最远的将要使用的页面淘汰,是一种最优的方案,不过预知未来难以做到

  3. LRU(OPT算法的可实现版本)

    使用历史来预测未来。选取最长时间没有使用的页面淘汰,也成为最近最少使用

    实现方法:

    • 计数器法

      每一个页维护一个时间戳,每一次访问该页的时候计数器+1,并将该值复制到相应页表项中。当需要置换页时,选则计数值最小的页。缺点:每次地址访问都需要修改时间戳,需维护一个全局时钟(该时钟溢出怎么办?),需要找到最小值 … 这样的实现代价较大几乎没人用。

    • 页码栈算法

      建立一个容量为有效帧数的页码栈。每当引用一个页时,该页号就从栈中上升到栈的顶部,栈底为LRU页。当需要置换页时,直接置换栈底页即可。缺点:每次地址访问都需要修改栈(修改10次左右栈指针) … 实现代价仍然较大 。

    LRU准确算法代价太大,因此出现了其近似算法:

  4. Clock算法

    每个页加一个引用位(reference bit),每次访问一页时,硬件自动设置该位为1。选择淘汰页:扫描该位,是1时清0,并继续扫描;直到碰到是0时淘汰该页,记录该位置,下次继续

    具体如下:

    • 将可用帧按顺序组成环形队列,引用位初始置0,并置指针初始位置;
    • 缺页时从指针位置扫描引用位,将1变0,直到找到引用位为0的页;
    • 当某页被替换,则指针移到该页的下1页。

    算法缺点:

    • 缺页很少,标志就会全为1,最后退化位FIFO,因为记录了太多的历史信息(可以定时清除标志位,速度需要合适,太快也会退化位FIFO),

    实际算法中可以动态设置清除周期的速度,主要看空闲内存比例来决定。

虚拟内存中的其他问题

  1. 写时复制

    为了更快的地创建进程,子进程共享父进程的地址空间,仅当子进程需要更改数据时才复制产生新的页

  2. 换出的页存放到哪里

    • windows 普通的文件系统中
    • linux,放在swap分区中,是一块生磁盘
    • 系统拥有足够的交换区空间:可以全部从对换区调入所需页面,以提髙调页速度。为此,在进程运行前,需将与该进程有关的文件从文件区复制到对换区。
    • 系统缺少足够的对换区空间:凡不会被修改的文件都直接从文件区调入;而当换出这些页面时,由于它们未被修改而不必再将它们换出。但对于那些可能被修改的部分,在将它们换出时须调到对换区,以后需要时再从对换区调入。
    • UNIX方式:与进程有关的文件都放在文件区,故未运行过的页面,都应从文件区调入。曾经运行过但又被换出的页面,由于是被放在对换区,因此下次调入时应从对换区调入。进程请求的共享页面若被其他进程调入内存,则无需再从对换区调入。
  3. 工作集

    即给进程分配的主存物理空间。操作系统如何决定分配给进程的物理内存空间,下面是需要考虑的问题

    • 分配给一个进程的存储量越小,在任何时候驻留在主存中的进程数就越多,从而可以提高处理机的时间利用效率。
    • 如果一个进程在主存中的页数过少,尽管有局部性原理,页错误率仍然会相对较高。
    • 如驻留集过大,由于局部性原理,给特定的进程分配更多的主存空间对该进程的错误率没有明显的影响。

    工作集的两种分配方式:

    • 固定分配:工作集大小固定,可以:各进程平均分配,根据程序大小按比例分配,按优先权分配。
    • 可变分配:工作集大小可变,按照缺页率动态调整(高或低->增大或减小常驻集),性能较好。增加算法运行的开销。
  4. 置换策略

    • 全局置换:(可以淘汰其他人的页面)简单但是不能实现公平
    • 局部置换:需要考虑给进程分配多少页框(过多过少都不合适)
  5. 系统运行过程中可能CPU的利用率大幅下降

    每个进程的缺页率增大 ,缺页率增大到一定程度,进程总等待调页完成 ,CPU利用率降低,进程进一步增多,缺页率更大

    这一现象称为”颠簸“,防止的根本手段给进程分配足够多的帧。但是分配多少合适呢。

    Belady异常:对有的页面置换算法,页错误率可能会随着分配帧数增加而增加。

    什么样的页面置换没有belady异常:LRU栈实现没有。

  6. 虚拟内存中程序的优化

    根据程序的局部性原理,尽量将一起访问的代码放到一起

相关内容推荐