主要内容

  • 起因
  • 覆盖技术
  • 交换技术
  • 虚存技术
    • 目标
    • 程序局部性原理
    • 基本概念
    • 基本特征
    • 虚拟页式内存管理

起因

程序规模的增长速度远远大于存储器容量的增长速度。因此要想一些办法,让更多的程序跑在有限的内存里面。

理想中的存储器

更大,更快,更便宜非易失性存储器

实际中的存储器

在计算机体系结构中我们曾经提到过,容量更小,速度更快的存储器存放在靠近CPU的地方,而容量大,速度较慢的存储器相对离CPU更远。存储器的速度和容量如下图所示:

 

现有的存储体系无法做到既满足速度,又满足容量容量,但人总是贪心的,一直想着要兼顾这两者。

 

 

  从上图来看,在OS的内核上会运行很多的程序,仅靠内存是无法容纳的,一个解决问题的思路是,硬盘容量大,我们希望借助操作系统的管理,所以要想办法把硬盘的容量用上,将不常用的数据放到硬盘上去,硬盘的速度远不如内存,所以将常用的数据和程序放在内存里面,以保证程序的运行速度。由此,就创造一个虚拟的存储空间,做到了速度和容量的兼顾。

 覆盖技术

如果是程序太大,超过了内存的容量,可以采用手动的覆盖(overlay)技术,只把需要的指令和数据保存在内存当中。

目标:是在较小的可用内存中运行较大的程序。常用于多道程序系统,与分区存储管理配合使用。代表是DOS操作系统。 

原理:

    • 把程序按照其自身逻辑结构,划分为若干个功能上相对独立的程序模块,那些不会同时执行的模块共享同一块内存区域,按时间先后来运行。
    • 必要部分(常用功能)的代码和数据常驻内存;
    • 可选部分(不常用功能)在其他程序模块中实现,平时存放在外存中,在需要用到时才装入内存;
    • 不存在调用关系的模块不必同时装入到内存,从而可以相互覆盖,即这些模块共用一个分区。

  下面来看一个例子:程序X共有A,B,C,D,E,F六个模块,加起来占用了190K的内存空间,基于逻辑调用关系可以进行分类,不具有逻辑调用关系的模块被分入相同的分区,如B,C被分入覆盖区0,D,E,F被分入覆盖区1,A因为较常用,被分入常驻区。程序A运行时,如果调用B,则将硬盘中的B装入覆盖区0,如果B再调用D,则将D装入覆盖区1;调用结束后,覆盖区的内存会被释放,所以D与B占据的空间会被释放;然后A继续调用C,操作系统将C装入覆盖区0,C函数如果调用E,则将E被装入覆盖区1,如果调用F,则将F装入覆盖区1。这样,程序运行过程中不需要把所有模块一次性全部装入内存,而是将存在调用关系的模块同时装入内存,当有新的调用发发生时,新的模块会装入内存替换旧模块。

根据逻辑调用关系,可以手动确定多种覆盖方式。如上图,B,E,F可以共用一个分区,C,D共用一个分区,这样所需的内存更小(100K)。

缺点:

    • 由程序员来把一个大的程序划分为若干个小的功能模块,并确定各个模块之间的覆盖关系,费时费力,增加了编程的复杂度;
    • 覆盖模块从外存装入内存,实际上是以时间延长来换取空间节省。

交换技术

如果是程序太多,超过了内存的容量,可以采用自动的交换(swapping)技术,把暂时不能执行的程序送到外存中,Unix系统采用的就是这种方法。

目标:多道程序在内存中时,让正在运行的程序或需要运行的程序获得更多的内存资源。

方法:

    • 可将暂时不能运行的程序送到外存,从而获得空闲内存空间。
    • 操作系统把一个进程的整个地址空间的内容保存到外存中(换出swap out) ,而将外存中的某个进程的地址空间读入到内存中(换入swap in)。换入换出内容的大小为整个程序的地址空间,如上图所示。

交换技术实现中的几个问题:

    • 交换时机的确定:何时需要发生交换?只当内存空间不够或有不够的危险时换出。
    • 交换区的大小:必须足够大以存放所有用户进程的所有内存映像的拷贝;必须能对这些内存映像进行直接存取。
    • 程序换入时的重定位:换出后再换入的内存位置一定要在原来的位置上吗?最好采用动态地址映射的方法。

覆盖与交换的比较

    • 覆盖只能发生在那些相互之间没有调用关系的程序模块之间,因此程序员必须给出程序内的各个模块之间的逻辑覆盖结构。
    • 交换技术是以在内存中的程序大小为单位来进行的,它不需要程序员给出各个模块之间的逻辑覆盖结构。换言之,交换发生在内存中程序与管理程序或操作系统之间,而覆盖则发生在运行程序的内部。

虚存技术

 

在内存不够用的情形下,可以采用覆盖技术和交换技术,但是:

 

    • 覆盖技术:需要程序员自己把整个程序划分为若干个小的功能模块,并确定各个模块之间的覆盖关系,增加了程序员的负担;
    • 交换技术:以进程作为交换的单位,需要把进程的整个地址空间都换进换出,增加了处理器的开销。

 

如果想要在有限容量的内存中,以更小的页粒度为单位装入更多更大的程序,可以采用自动的虚拟存储技术。

 

在上图中,有P1~P4四个程序,在某一时间段,程序P3运行只需要两个内存页,其他数据全都放在硬盘上,所以就不需要把整个P3全部放入内存当中,解决了内存空间不足的问题。

目标:

    • 虚存技术像覆盖技术那样,不是把程序的所有内容都放在内存中,因而能够运行比当前的空闲内存空间还要大的程序。但做得更好,由操作系统自动来完成,无须程序员的干涉;
    • 像交换技术那样,能够实现进程在内存与外存之间的交换,因而获得更多的空闲内存空间。但做得更好,只对进程的部分内容在内存和外存之间进行交换。

在虚拟内存中,需要程序满足局部性原理

程序局部性原理:程序的局部性原理(principle of locality):指程序在执行过程中的一个较短时期,所执行的指令地址和指令的操作数地址,分别局限于一定区域。这可以表现为:

    • 时间局部性:一条指令的一次执行和下次执行,一个数据的一次访问和下次访问都集中在一个较短时期内;
    • 空间局部性:当前指令和邻近的几条指令,当前访问的数据和邻近的几个数据都集中在一个较小区域内。

  程序的局部性原理表明,从理论上来说,虚拟存储技术是能够实现的,而且在实现了以后应该是能够取得一个满意的效果的。下面我们来看一个例子,这个例子反映了程序编写对缺页率的影响:

页面大小为4K,分配给每个进程的物理页面数为1。在一个进程中,定义了如下的二维数组int AI024][1024],该数组按行存放在内存,每一行放在一个页面中。

程序编写方法1:           程序编写方法2:

for(j=0;j<1024;j++)      for(i=0;i<1024;i++)

for(i=0;i<1024;i++)      for(j=0;j<1024;j++)

           A[il][lj]= 0;              A[il][lj]= 0;

  在C语言中,是按照行优先规则来放置数组的:

  a0,0   a0,1   a0,2    ....................    a0,1023                                      1

  a1,0   a1,1   a1,2    ....................    a1,1023                                      2

  .....................................

  .....................................

  a1023,0   a1023,1   a1023,2    ....................    a1023,1023                 1024

  两种方法访问页面的顺序为:

  解法一:1,2,3,…………,1024,1,2,………… 共1024组共发生了1024×1024次缺页中断

  解法二:1,1,1,…………,2,2,...……,3,3,…. 共发生了1024次缺页中断

  由此可见,考虑局部性原理后,可以大大降低缺页率

 

虚拟存储——基本概念

    • 在装入程序时,不必将其全部装入到内存,而只需将当前需要执行的部分页面或段装入到内存,就可让程序开始执行;
    • 在程序执行过程中,如果需执行的指令或访问的数据尚未在内存(称为缺页或缺段),则由处理器通知操作系统将相应的页面或段调入到内存,然后继续执行程序;
    • 另一方面,操作系统将内存中暂时不使用的页面或段调出保存在外存上,从而腾出更多空闲空间存放将要装入的程序以及将要调入的页面或段。

虚拟内存——基本特征

    • 大的用户空间:通过把物理内存与外存相结合,提供给用户的虚拟内存空间通常大于实际的物理内存,即实现了这两者的分离。如32位的虚拟地址理论上可以访问4GB,而可能计算机上仅有256M的物理内存,但硬盘容量大于4GB。
    • 部分交换:与交换技术相比较,虚拟存储的调入和调出是对部分虚拟地址空间进行的;
    • 不连续性:物理内存分配的不连续,虚拟地址空间使用的不连续。

虚拟页式内存管理

 

 

  大部分虚拟存储系统都采用虚拟页式存储管理技术,页式存储管理通过页表(page table)完成逻辑页(logical pages)到物理页帧(physical frames)的映射,虚拟页式管理即在页式存储管理的基础上,增加请求调页页面置换功能。

基本思路:

    • 当一个用户程序要调入内存运行时,不是将该程序的所有页面都装入内存,而是只装入部分的页面,就可启动程序运行。
    • 在运行的过程中,如果发现要运行的程序或要访问数据不在内存,则向系统发出缺页中断请求,系统在处理这个中断时,将外存中相应的页面调入内存,使得该程序能够继续运行。

为了实现请求调页和页面置换,需要在页表中增加一些位:

  • 驻留位:表示该页是在内存还是在外存。如l果该位等于1,表示该页位于内存当中,即该页表项是有效的,可以使用;如果该位等于0,表示该页当前还在外存当中,如果访问该页表项,将导致缺页中断。
  • 保护位:表示允许对该页做何种类型的访问,如只读、可读写、可执行等。
  • 修改位:表明此页在内存中是否被修改过。当系统回收该物理页面时,根据此位来决定是否把它的内容写回外存。
  • 访问位:如果该页面被访问过(包括读操作或写操作),则设置此位。用于页面置换算法。

下面说个例子,展示这些为如何影响带调页和置换。在下图中,X代表驻留位为0,否则驻留位为1。

  如果访问逻辑地址为0的页,可以得到页帧号为2,物理地址为2x4096=8192;如果访问逻辑地址为32780的页,发现该地址处页帧号为X,说明对应的页帧不在内存中,此时就会产生缺页中断

 

 

缺页中断的处理过程:

1.如果在内存中有空闲的物理贞面。则分配一物理页帧f。然后转第4步:否则转第2步;

2.采用某种页面置换算法。选择一-个将被替换的物理页帧f。它所对应的逻辑页为q。如果该页在内存期间被修改过。则需把它写网外存;

3.对q所对应的页表项进行修改,把驻留位置为0;

4.将需要访问的页p装入到物理页面r当中;

5.修改p所对应的页表项的内容,把驻留位置为1。把物理页帧号置为f;

6.重新运行被中断的指令。

问题:在何处保存未被映射的页?

    • 能够简单地识别在二级存储器(后备存储)中的页
    • 交换空间(磁盘或者文件):特殊格式,用于存储未被映射的页面

后备存储 backing store

    • 一个虚拟地址空间的页面可以被映射到一个文件(在二级存储中)中的某个位置
    • 代码段:映射到可执行二进制文件
    • 动态加载的共享库程序段:映射到动态调用的库文件
    • 其它段:可能被映射到交换文件(swap file)

虚拟内存性能:

为了便于理解分页的开销,使用有效存储器访问时间effective memory access time (EAT)来分析:

EAT=访存时间*页表命中几率+page fault处理时间*page fault几率

例子:

访存时间:10 ns

磁盘访问时间:5 ms

参数p =page fault几率

参数q= dirty page几率

EAT=10(1-p)+ 5,000,000p(1+q)