• 第八章 虚拟内存


    一、虚拟内存基本概念

    1.局部性原理

    (1)时间局部性: 程序中的某条指令一旦运行,不久以后该指令可能再次运行。产生时间局部性的典型原因是由于程序中存在着大量的循环操作。

    (2)空间局部性: 一旦程序访问了某个存储单元,不久以后其附近的存储单元也将被访问,其典型情况是程序顺序运行。

    2.虚拟内存

    基于局部性原理,应用程序在运行之前并不必全部装入内存,仅需将当前运行到的那部分程序和数据装入内存便可启动程序的运行,其余部分仍驻留在外存上。当要运行的指令或访问的数据不在内存时,再由操作系统通过请求调入功能将它们调入内存,以使程序能继续运行。如果此时内存已满,则还需通过置换功能,将内存中暂时不用的程序或数据调至盘上,腾出足够的内存空间后,再将要访问的程序或数据调入内存,使程序继续运行。
    

    3.实现虚拟内存的基础

    硬件基础
    一定容量的内存;
    大容量的外存;
    地址变换机构(含快表);
    缺页中断机构。

    软件基础
    虚实转换的数据结构(页表、段表等);
    中断服务处理程序;
    操作系统支持。

    实现虚拟的方案:

    页式虚存(请求分页:最常用)
    
    段式虚存
    
    段页式虚存
    

    4.虚拟内存的主要特征

    (1)多次性。
    
    (2)对换性。
    
    (3)虚拟性。
    

    5.虚拟内存、逻辑地址、线性地址、物理地址

    逻辑地址(Logical Address) 是指由程序产生的与段相关的偏移地址部分。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制,Cpu不进行自动地址转换);逻辑也就是在Intel 保护模式下程序执行代码段限长内的偏移地址(假定代码段、数据段如果完全一样)。应用程序员仅需与逻辑地址打交道,而分段和分页机制对您来说是完全透明的,仅由系统编程人员涉及。应用程序员虽然自己可以直接操作内存,那也只能在操作系统给你分配的内存段操作。

    线性地址(Linear Address) 是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G(2的32次方即32根地址总线寻址)。

    物理地址(Physical Address) 是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了。

    虚拟内存(Virtual Memory) 是指计算机呈现出要比实际拥有的内存大得多的内存量。因此它允许程序员编制并运行比实际系统拥有的内存大得多的程序。这使得许多大型项目也能够在具有有限内存资源的系统上实现。一个很恰当的比喻是:你不需要很长的轨道就可以让一列火车从上海开到北京。你只需要足够长的铁轨(比如说3公里)就可以完成这个任务。采取的方法是把后面的铁轨立刻铺到火车的前面,只要你的操作足够快并能满足要求,列车就能象在一条完整的轨道上运行。这也就是虚拟内存管理需要完成的任务。在Linux 0.11内核中,给每个程序(进程)都划分了总容量为64MB的虚拟内存空间。因此程序的逻辑地址范围是0x0000000到0x4000000。

    有时我们也把逻辑地址称为虚拟地址。因为与虚拟内存空间的概念类似,逻辑地址也是与实际物理内存容量无关的。

    逻辑地址与物理地址的“差距”是0xC0000000,是由于虚拟地址->线性地址->物理地址映射正好差这个值。这个值是由操作系统指定的。

    虚拟地址到物理地址的转化方法是与体系结构相关的。一般来说有分段、分页两种方式。以现在的x86 cpu为例,分段分页都是支持的。Memory Mangement Unit负责从虚拟地址到物理地址的转化。逻辑地址是段标识+段内偏移量的形式,MMU通过查询段表,可以把逻辑地址转化为线性地址。如果cpu没有开启分页功能,那么线性地址就是物理地址;如果cpu开启了分页功能,MMU还需要查询页表来将线性地址转化为物理地址:
    逻辑地址 —-(段表)—> 线性地址 — (页表)—> 物理地址
    不同的逻辑地址可以映射到同一个线性地址上;不同的线性地址也可以映射到同一个物理地址上;所以是多对一的关系。另外,同一个线性地址,在发生换页以后,也可能被重新装载到另外一个物理地址上。所以这种多对一的映射关系也会随时间发生变化。

    二、请求分页管理方式

    1.请求分页的基本原理

    请求分页存储管理是在简单分页管理基础上发展起来的。请求页式管理在作业或进程开始执行之前,不要求把作业或进程的程序段和数据段一次性地全部装入内存,而只把当前需要的一部分页面装入内存,其它部分在作业执行过程中需要时,再从外存上调入内存。
    

    2.页表的扩充

    (1)存在位(present/absent):表示该页是否在内存。
    
    (2)修改位(modified):该位为“0”时,在示访页面中的数据未被修改过。
    
    (3)引用位(referenced):表示该页面在最近期间是否被访问引用过。
    
    (4)外存地址(swaparea address):指出该页面在外存上的存放地址。
    
    (5)其它:如页面保护位(protection),禁止缓存位(cachedisabled)等。
    

    3.地址变换

    请求分页的地址变换初始过程十分类似于简单分页系统的地址变换。
    

    4.缺页中断处理

    当存在位为0时,表示该页不在内存,则必须确定它在外存中的存放地址。并把它从外存中调入内存。若内存中没有空闲块时,首先按照某种策略选择某页进行淘汰。以腾出空闲块供本次调入的页占用。这个过程也被称之为页面置换。若被选中淘汰的页面中的信息修改过(修改位=1)还必须将其写回外存。如内存中有空闲块,则根据该页在外存的地址,调入所需页面,并更新页表表项,最后恢复被中断的指令重新执行。
    

    5.调页策略

    这是一个何时把页面装入内存的问题。如果出现缺页中断,表明企图对一个不存在于内存的页面要求访问。显然,应该立即装入该页面。这种仅当需要时才调取页面的策略,称为请求式调页,采用请求式调页策略的分页系统称为请求式分页;而把事先调取页面的策略称为预调页。
    

    三、页面置换算法

    1.随机淘汰算法

    在无法确定那些页被访问的概率较低时,随机地选择某个用户的页面并将其换出。
    

    2.先进先出算法(FIFO)

    FIFO(firstin first out)算法:总是选择驻留内存时间最长的页面进行淘汰。其理由是:最早调入内存的页面,其不再被使用的可能性最大。
    
    FIFO算法忽略了一种现象的存在,就是在内存中停留时间最长的页往往也是经常被访问的页。将这些页淘汰,很可能刚置换出去,又请求调用该页,致使缺页中断较频繁,严重降低内存的利用率。
    
    FIFO的另一缺点是它有一种异常现象。称为Belady异常。
    

    3.最佳置换算法(OPT)

    最佳置换算法的基本思想是:从内存中移出永远不再需要的页面。
    

    4.最近最久未使用页面置换算法(LRU)

    这种算法的基本思想是,利用局部性原理,根据一个作业在执行过程中过去的页面访问历史来推测未来的行为。它认为过去一段时间里不曾被访问过的页面,在最近的将来可能也不会再被访问。
    

    5.最近没有使用页面置换算法(NRU)

    该算法只要求对应于每个存储块(页面)设置一个“引用位”和“修改位”。利用这二组织成四种状态,“引用位”:“修改位”=0:0;0:1;1:0;1:1。每次置换时,总取最小值的页面置换,若相同则随机置换或先进先出置换。
    

    6.时钟算法(CLOCK)

    时钟算法是将作业已调入内存的页面链成循环队列,使用页表中的“引用位”,用一个指针指向循环队列中的下一个将被替换的页面。
    

    四、页面分配策略

    1.固定分配局部置换策略
    
    2.可变分配全局置换策略
    
    3.可变分配局部置换策略
    

    五、工作集

    工作集也称为驻留集,是某一个进程调入物理内存的页面的集合,这些页面是频繁地被使用到的,因此长期驻留内存是有利于提高处理机的效率。工作集模型是基于局部性原理假设的。
    

    六、抖动

    如果分配给进程的存储块数量小于进程所需要的最小值,进程的运行将很频繁地产生缺页中断。这种频率非常高的页面置换现象称之为抖动(也称为颠簸)。往往是刚被淘汰的页面马上被选中调页而进入内存。抖动将引起严重的系统性能下降。
    
    防止抖动现象有多种办法,例如,采取局部替换策略,引入工作集算法,挂起或撤销若干进程等。
    

    九、其他考虑
    1、预调页
    纯按需调页的一个显著特性是当一个进程开始时会出现大量页错误。而预调页的策略是同时将所需的所有页调入内存。关键是成本是否小于相应页错误的成本。

    2、页大小
    该用大页还是小页,是个问题。
    1)大页有利于减少页表
    2)小页有利于减少碎片,可更好地利用内存
    3)小页传输快,大页IO好,但又不一定,小页因为寻址、传输快,局部性得以改善,总的IO就会降低,那么,应该用小页?
    4)然而,大页可以降低页错误数量
    ……
    切克闹,现在你告诉我,该用大页还是小页?

    3、TLB范围
    TLB可提高内存访问速度,如果没有TLB,则每次取数据都需要两次访问内存,即查页表获得物理地址和取数据。
    TLB只维护页表中的一小部分条目,逻辑地址转换物理地址过程中,先在TLB中查找,如果找到,那么物理地址唾手可得;如果TLB中没有,那么使用置换算法,将相关条目置换进TLB,然后再得到物理地址。
    那么提高TLB命中率至关重要。
    提高TLB命中率可增加TLB条数,但代价不小,因为用于构造TLB的相关内存既昂贵又费电。另一个方法是增加页的大小,或提供多种页大小。

    4、反向页表
    反向页表可以节省内存,不过,当进程所引用的页不在内存中时,仍然需要一个外部页表以获得物理帧保存哪个虚拟内存页面的信息。所幸这只是在页错误时才需要用到,外部页表本身可以换出换入,不苛求一定完备。

    5、I/O互锁
    允许页在内存中被锁住。
    在全局置换算法中,一个进程发出IO请求,被加入到IO设备等待队列,而CPU交给了其他进程。这些进程发生页错误,偏偏置换了等待进程用于IO的缓存页,这些页被换出。好了,请求IO的进程等待到了IO设备,针对指定地址进行IO,然而帧早被其他进程的不同页所使用。

    对这个问题,通常有两种解决方法:
    1)绝不对用户内存进行IO,如果要进行IO,将用户内存数据复制到系统内存。要复制一次,开销太高了。
    2)物理帧有一个锁住位,允许页锁在内存中。如果锁住,则不能置换。当IO完成,页被解锁。
    锁住位用处多多,比如操作系统内核页通常加锁;低优先级进程的页至少要运行一次才能解锁被置换。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    DockerAPI版本不匹配的问题
    Linux文件系统
    队列

    多维数组
    字符串
    线性表
    ARM编辑、编译工具
    南京IT公司
    数据结构:用单链表实现的队列(2)
  • 原文地址:https://www.cnblogs.com/yangquanhui/p/4937490.html
Copyright © 2020-2023  润新知