虚拟内存

来源:互联网 发布:openwrt mac地址 编辑:程序博客网 时间:2024/05/18 12:36

分页
大小不等的固定分区和大小可变的分区技术在内存使用上都是低效的,前者会产生内部碎片,后者会产生外部碎片。但是,假如内存被分成大小固定相等的块,且块相对比较小,每个进程也被分成同样大小的小块,那么进程中称为页的块可以指定到内存中称为页框的可用块。使用分页技术在内存中为每个进程浪费的空间,仅仅是进程最后一页的一小部分形成的内部碎片。
这里写图片描述

操作系统为每个进程维护一个页表。页表给出了该进程的每一页对应的页框的位置。在程序中,每个逻辑地址包括一个页号和在该页中的偏移量。给出逻辑地址(页号和偏移量),处理器使用页表产生物理地址(页框号,偏移量)。

各个进程的页表
这里写图片描述

进程每一页在页表中都有一项,因此页表可以很容易的按页号对进程的所有页进行索引(从0页开始)。每个页表项包含内存中的用于保存相应页的页框的页框号。

为了使分页方案更加方便,规定页的大小及页框的大小必须是2的幂。相对地址由程序起点和逻辑地址定义,可以用页号和偏移量表示。
这里写图片描述

考虑一个n+m位的地址,最左边的n位是页号,最右边的m位是偏移量。在上图(b)中,n=6且m=10。地址转换需要以下步骤:

  • 提取页号,即逻辑地址最左面的n位;
  • 以这个页号为索引,查找该进程页表中相应的页框号;
  • 该页框的起始物理地址为kx2的m次幂,被访问字节的物理地址是这个数加上偏移量。

逻辑地址为0000010111011110,它的页号为1,偏移量为478。该页驻留在内存页框6中,则物理地址页框号为6,偏移量为478,物理地址为0001100111011110。
这里写图片描述

总之,采用简单分页技术,内存被分成许多大小相等且很小的页框,每个进程被划分成同样大小的页;较小的进程需要较少的页,较大的进程需要较多的页。当一个进程被装入时,它的所有页都被装入到可用页框中,并且建立一个页表。

分段

采用分段技术,可以把程序和其相关的数据划分到几个段中。尽管段有一个最大长度限制,但并不要求所有程序的所有段的长度都相等。采用分段技术时的逻辑地址也是由两部分组成的:段号和偏移量。

由于使用大小不等的段,分段类似于动态分区。在分段方案中,一个程序可以占据占据多个分区,并且这些分区不要求是连续的。

分页对程序员来说是透明的,而分段通常是可见的。必须清楚段的最大长度限制。

采用大小不等的段另一个结果是,逻辑地址和物理地址间不再具有简单的对应关系。在简单的分段方案中,每个进程都有一个段表,系统也会维护一个内存中的空闲块列表。每个段表项必须给出相应的段在内存中的起始地址,还必须指明段的长度,以确保不会使用无效地址。

考虑一个n+m位的地址,最左边的n位是段号,最右边的m位是偏移量。进行地址转换的步骤:

  • 提取段号,即逻辑地址最左边的n位;
  • 以这个段号为索引,查找该进程段表中该段的其实物理地址;
  • 最右边m位表示偏移量,偏移量和段长度进行比较,如果偏移量大于该段的长度,则这个地址无效。
  • 物理地址为该段的起始物理地址与偏移量的和。

逻辑地址为0001001011110000,其中段号为1,偏移量为752。假设该段驻留在内存中,起始物理地址为0010000000100000,则相应的物理地址为0010000000100000+001011110000=0010001100010000。
这里写图片描述

内存管理同处理器硬件和操作系统软件有着紧密而复杂的关系。
这里写图片描述

硬件和控制结构

  • 进程中的所有内存访问都是逻辑地址,这些逻辑地址在运行时动态地转换为物理地址。
  • 一个进程可以划分成许多块(页和段),在执行过程中,这些块不需要连续地位于内存中。

如果具备前面的两个特点,那么进程的执行过程中,该进程不需要所有页或所有段都在内存中。

有两种实现方法可以提高系统的利用率:

  • 在内存中保留多个进程
  • 进程可以比内存的全部空间还大

由于一个进程只能在内存中执行,因此这个存储器称为实存储器,简称实存。但是程序员或用户感觉到的是一个更大的内存,通常它被分配在磁盘上,这称为虚拟内存。虚存支持更有效的多道程序设计,并解除了用户与内存之间没有必要的紧密约束。

总结了使用虚存和不使用虚存的情况下分页和分段的特点
这里写图片描述

这里写图片描述

局部性和虚拟内存

在任何时刻,任何一个进程只有一部分块位于内存中,可以在内存中保留更多的进程。

局部性原理描述了一个进程中程序和数据的引用的集簇倾向。因此,在很短的时间内仅需要进程的一部分块是合理的。

局部性原理说明了虚拟内存方案是可行的。为了使虚存比较实用并且有效,需要两方面的因素。首先,必须有对所采用的分页或分段方案的硬件支持;第二,操作系统必须有管理页或段在内存和辅助存储器(辅存)之间移动的软件。

分页

当考虑基于分页的虚拟内存方案时,也同样需要页表,并且通常每个进程都有一个唯一的页表。但这时页表项变得更复杂。由于一个进程可能只有一些页在内存中,因此每个页表项需要由一个位(P)来表示它所对应的页当前是否在内存中。如果这一位表示该页在内存中,则这个页表项还包括该页的页框号。

页表结构

从内存中读取一个字的基本机制包括使用页表从虚拟地址到物理地址的转换。虚拟地址又称为逻辑地址,由页号和偏移量组成,而物理地址由页框号和偏移量组成。

在大多数系统中,每个进程都有一个页表。但是每个进程可以占据大量的虚存空间。大多数虚拟内存方案都在虚存而非实存中保存页表。这意味着页表和其他页一样都服从分页管理。当一个进程正在运行时,它的页表至少有一部分必须在内存中,这一部分包括正在运行的页的页表项。
这里写图片描述

倒排页表

页表设计的一个重要缺陷是,页表的大小与虚拟地址空间的大小成正比。

在这种方法中,虚拟地址的页号部分使用一个简单散列函数映射到散列表中。散列表包含一个指向倒排表的指针,而倒排表中含有页表项。通过这一结构,散列表和倒排表中各有一项对应于一个实存页,而不是虚拟页。

对于大小为2的m个页框的物理内存,倒排页表包含2的m次方项,所以第i个项对应于第i个页框。页表中的每项都包含如下内容:

  • 页号:虚拟地址的页号部分
  • 进程标志符:使用该页的进程。
  • 控制位:该域包含一些标记,比如有效、访问和修改;以及保护和锁定消息。
  • 链指针

虚拟地址包含一个n位的页号,并且n>m。散列函数映射n位页号到m位数,这个m位数用于索引倒排页表。

转换检测缓冲区

原则上,每个虚存访问可能引起两次物理内存访问:一次取相应的页表项,一次取需要的数据。因此,简单的虚拟内存方案导致内存访问时间加倍。为克服这一问题,大多数虚拟内存方案为页表项使用一个特殊的高速缓存,通常称为转换检测缓冲区。
这里写图片描述

这里写图片描述

这里写图片描述

页尺寸

页尺寸是一个重要的硬件设计决策,需要考虑多方面的因素。其中一个因素是内部碎片。显然,页越小,内部碎片的总量越少。另一方面,页越小,每个进程需要的页的数目就越多,这就意味着更大的页表。

对于多道程序设计环境中的大程序,这就意味着活动进程有一部分页表在虚存中,而不是内存中。从而一次内存访问可能产生两次缺页中断:第一次读取所需的页表部分,第二次读取进程页。

分段

分段允许程序员把内存视为由多个地址空间或段组成,段的大小是不相等的,并且是动态的。内存访问以段号和偏移量的形式组成的地址。

组织 在简单分段时,曾指出每个进程都有自己的段表,当它的所有段都装入内存时,为该进程创建一个段表并装入内存。基于分段的虚拟内存方案,每个进程都有一个唯一的段表。在这种情况下,段表项变得更加复杂。由于一个进程可能只有一部分段在内存中,因而每个段表项中需要有一位表明相应的段是否在内存中。如果这一位表明该段在内存中,则这个表项还包括该段的起始地址和长度。

段表项中需要的另一个控制位是修改位,用于表明相应的段从上一次被装入内存到目前为止其内容是否被改变。如果未改变,把该段换出时就不需要写回。

从内存读一个字的基本机制涉及使用段表来将段号和偏移量组成的虚拟地址转换成物理地址。

当一个特定的进程正在运行时,有一个寄存器为该进程保存段表的起始地址。虚拟地址中的段号用于检索这个表,并查找该段起点的相应内存地址。这个地址加上虚拟地址中的偏移量部分,产生了需要的实地址。

段页式

在段页式的系统中,用户的地址空间被程序员划分为许多段。每个段依次划分成许多固定大小的页,页的长度等于内存中的页框大小。如果一段的长度小于一页,则该段只占据一页。逻辑地址仍然由段号和偏移量组成;从系统的角度看,段偏移量可视为指定段中的一个页号和偏移量。

每个进程使用一个段表和一些页表,并且每个进程段使用一个页表。当一个特定的进程运行时,使用一个寄存器记录该进程段表的起始地址。对于一个虚拟地址,处理器使用段号部分来检索进程段表以寻找该段的页表。然后虚拟地址的页号部分用于检索页表并查找相应的页框号。
这里写图片描述

保护和共享

分段有助于实现保护与共享机制。由于每个段表项包括一个长度和一个基地址,因而程序不会不经意的访问超出该段的内存单元。为实现共享,一个段可能在多个进程的段表中被引用。程序的页结构和数据对程序员是不可见的,使得共享和保护的要求难以说明。

操作系统软件

操作系统的内存管理设计取决于三个基本方面的选择:

  • 是否使用虚存技术
  • 是使用分页还是使用分段,或者是二者的组合
  • 为各种存储管理特征采用的算法

前两方面中的选择取决于使用的硬件平台。第三方面相关的选择属于操作系统软件领域的问题,列出了需要考虑的重要设计因素。
这里写图片描述

读取策略 确定一个页何时取入内存,常用请求分页和预先分页。对于请求分页,只有当访问到某页中的一个单元才将该页取入内存。

对于预先分页,读取的页并不是缺页中断请求的页。如果一个进程的页被连续存储在辅存中,则一次读取许多连续的页比隔一段时间读取一页更有效。如果大多数额外读取的页没有引用到,则这个策略是低效的。

当进程第一次启动时,可以采用预先分页策略,在这种情况下,程序员必须以某种方式指定需要的页。

放置策略决定一个进程块驻留在实存中的什么地方。

置换策略 用于处理在必须读取一个新页时,应该置换内存中的哪一页。

  • 给每个活动进程分配多少页框
  • 计划置换页的集合是局限在那些产生缺页中断的进程,还是所有页框都在内存中的进程。
  • 在计划置换的页集中,选择换出哪一页

当内存中的所有页框都被占据,并且需要读取一个新页以处理一次缺页中断时,置换策略决定当前在内存的哪个页将被置换。

页框锁定内存中的某些页框可能是被锁定的。如果一个页框被锁定时,当前保存在该页框的页就不能被置换。大部分操作系统内核和重要的控制结构保存在锁定的页框中。锁定时通过给每个页框关联一个lock位实现的。

置换算法:

  • 最佳(optimal,OPT);
  • 最近最少使用(Least Recently Used,LRU)
  • 先进先出(First in First out, FIFO)
  • 始终(clock)

OPT策略选择置换下次访问距当前时间最长的那些页,该算法能导致最少的缺页中断。

LRU策略置换内存中上次使用距当前最远的页。

FIFO策略把分配给进程的页框视为一个循环缓冲区,按循环方式移动页。它所需要的只是一个指针,这个指针在该进程的页框中循环。

最简单的时钟策略需要给每一页框关联一个附加位,称为使用位。当某一页首次装入内存时,则将该页框的使用位设置为1;当该页随后被访问到时,它的使用位也会被置为1。用于置换的候选框集合被视为一个循环缓冲区,并且有一个指针与之关联。当需要置换一页时,操作系统扫描缓冲区,以查找使用位被置为0的一个页框。每当遇到一个使用位为1的页框时,操作系统将该位重新置为0;如果过程开始时,缓冲区中所有页框的使用位均为0,则选择遇到的第一个页框置换。

如果一起考虑使用使用位和修改位,那么每一个页框都处于以下四种情况之一:

  • 最近未被访问,也未被修改(u=0;m=0)
  • 最近被访问,但未被修改(u=1;m=0)
  • 最近未被访问,但被修改(u=0;m=1)
  • 最近被访问,被修改(u=1;m=1)

总之,页面置换算法在缓冲区的所有页中循环,查找自从被取入到现在从未被修改过且最近没被访问过的页。

页缓冲

它的页面置换算法是最简单的FIFO。为了提高性能,被置换出的页不是被丢弃,而是被分配到以下;两个表之一:如果未被修改,则分配到空闲页链表;如果修改了,则分配到修改页链表。

空闲页链表包含着页中可以读取的一系列页框。被置换的页仍然保留在内存中。实际上,空闲页链表和修改页链表充当着页的高速缓存的角色。

驻留集管理

对于分页式的虚拟内存,在准备执行时,不需要把一个进程的所有页都读入内存。操作系统必须决定读取多少页,也就是,给特定的进程分配多大的内存空间。

固定分配策略:为一个进程在内存中分配固定数目的页框用于执行时使用。一旦在进程的执行过程中发生缺页中断,该进程的一页必须被它所需要的页面置换。

置换策略:置换策略的作用范围可以分为全局和局部两类。这两种类型的策略都是在没有空闲页框时由一个缺页中断激活的。局部置换策略仅仅在产生这次缺页的进程的驻留页中选择。而全局置换策略把内存中所有未被锁定的页都作为置换的候选页。
这里写图片描述

固定分配、局部范围 :分配给在内存中运行的进程的页框数固定。当发生一次缺页中断时,操作系统必须从该进程的当前驻留页中选择一页用于置换。

可变分配、全局范围:操作系统维护着一个空闲页框列表。当发生一次缺页中断时,一个空闲页框被添加到进程的驻留集中,并且该页被读入。因此,发生缺页中断的进程的大小会逐渐增大。

清除策略:用于确定何时将一个被修改过的页写回辅存。通常有两种选择:请求式清除和预约式清除。请求式清除:只有当一页被选择用于置换时才被写回辅存。预约式清除:将被修改的多个页在需要用到它们所占据的页框之前成批地写回辅存。

加载控制

加载控制会影响到驻留在内存中的进程数目,这称为系统并发度。加载控制策略在有效的内存管理中是非常重要的。如果某一时刻驻留的进程太少,所有进程都同时处于阻塞状态的概率比较大,因而会有许多时间花费在交换上。另一方面,如果驻留的进程太多,平均每个进程的驻留集合大小将会不够用,就会频繁发生缺页中断。

进程挂起:如果系统并发度被减小,则一个或多个当前驻留进程必须被挂起(换出)。

Linux内存管理

Linux虚拟内存

虚存寻址:Linux使用三级页表结构,每个表的大小都是一页:

  • 页目录:一个活动进程有一页目录,页目录中的每一项指向页中间目录中的一页。每个活动进程的页目录都必须在内存中。
  • 页中间目录:页中间目录可能跨越多个页。页中间目录中的每一项指向页表中的一页。
  • 页表:每个页表项指向该进程的一个虚拟页。

为使用三级页表结构,Linux虚拟地址被视为4个域组成。最左也最重要的域作为页目录的索引,接下来的域作为页中间目录的索引,第三个域作为页表的索引,第四个域给出在内存中被选中页中的偏移量。
这里写图片描述

页面分配

为增强往内存中读入页和从内存中写出页的效率,Linux定义了一种机制,用于把连续的页映射到连续的页框中。基于这一目的,它使用了伙伴系统。内核维护一系列大小固定的连续页框组,一组可以包含1,2,4,8,16和32 个页框。

页面置换算法

Linux页面置换算法基于时钟算法。在Linux 方案中,使用位被一个8位的age变量所取代。每当一页被访问时,age变量增1。在后台,Linux周期性地扫描全局页池,并且当它在内存中的所有页间循环时,将扫描的每一页的age变量减1。age为0的页是一个“旧页”,有较长一段时间未被访问,是用于置换的最佳候选页。

内核内存分配

Linux内核内存管理物理内存页框,它主要的功能是为特定的使用分配和回收页框。页框的可能拥有者包括用户空间进程、动态分配的内核数据、静态内核代码及页缓冲区。