OS之内存管理 ---基本的内存管理策略(二)

分段

基本方法

分段就是基于用户视图的内存管理方案。逻辑地址空间是由一组段构成的,每个段都有名称和长度。地址指定了段名称和段内偏移。因此用户通过两个量来指定地址:段名称段偏移
为了简单,进行对段的编号,是通过段号而不是段名称来引用的,所以逻辑地址由有序对组成:<段号,偏移>。

分段硬件

用户是通过二位地址来引用程序内的对象的,但是实际物理内存仍然是一维的字节序列。所以我们需要定义一个实现方式,用来映射用户定义的二维地址到一维的物理地址。这个地址是通过段表来实现的。段表的每个条目都有段基地址和段界限。段基地址包含该段在内存中的开始物理地址,段界限指定该段的长度。
在这里插入图片描述
段表的使用如上图所示,每个逻辑地址由两部分组成:段号s和段偏移d。段号用作段表的索引,逻辑地址的偏移d应位于0和段界限之间。如果不是这样,那么会陷入操作系统中(逻辑地址试图访问段的外面);如果d合法,那么就与基地址相加而得到所需字节的物理内存地址。因此,段表实际上是基址寄存器值和界限寄存器值的对的数组。

分页

分段允许进程德尔物理地址空间是非连续的。分页是提供这种优势的另一种内存管理方案,使用分页可以避免外部碎片和紧缩。

基本方法

实现分页的基本方法涉及将物理内存分为固定大小的块,称为页帧;而将逻辑内存也分为同样大小的块,称为页面。当执行一个进程时,它的页从文件系统或备份存储等源处,加载到内存的可用帧。备份存储划分为固定大小的块,它与单个内存帧或与多个内存帧(簇)的大小一样。
分页的硬件如下图所示,由CPU生成的每个地址分为两部分:页码§和页偏移(d)。页码作为页表的索引。页表包含每页所在的物理内存的基地址。这个基地址和页偏移的组合就是物理内存的内存地址,可发送到物理单元。
在这里插入图片描述
页大小是由硬件决定的。页的大小为2的幂,如果逻辑地址空间为2m2^m,且页大小为2n2^n字节,那么逻辑地址的高m-n位表示页码,而低n位表示页偏移。
在这里插入图片描述
其中p为页表的索引,d为页的偏移。

采用分页方案不会产生外部碎片:每个空闲帧都可以分配给需要他的进程,但是,分页有内部碎片。分页是以帧为单位进行的,如果进程所要求的内存并不是页的整数倍,那么最后一个帧就用不完。如果进程大小与页大小无关,那么每个进程的内部碎片的均值为半页。

硬件支持

页表的硬件实现有多种方法,最简单的一种方法就是:将页表作为一组专用的寄存器来实现。这些寄存器应用告诉逻辑电路来构造,以高效的进行分页地址的转换。CPU分派器在加载其他寄存器的时候,也需要加载这些寄存器。注意,这种方法适用于页表比较小的情况下。
大多数的现代计算机都允许页表非常大,对于这种情况,需要将页表放在内存中,并将页表基址寄存器指向页表。改变页表只需要改变这一寄存器就行了。注意,如果采用这种方法,访问一个字节需要两次访问内存(一次用于页表条目,一次用于字节)。
标准方法是:采用转换表缓冲区(TLB),TLB是关联的高速内存,TLB条目是由两部分组成:键(标签)和值。当关联内存根据给定值查找时,它会同时与所有的键进行比较。如果找到条目,就得到相应值的字段。
TLB和页表一起使用的方法是:TLB只包含少数的页表条目。当CPU产生一个逻辑地址后,它的页码就发送到TLB。如果找到这个页码,它的帧码就立即可用,可用基于访问内存。如果页码不在TLB中,也就是TLB未命中。那么就需要访问页表。有的TLB在每个TLB条目中还保存地址空间标识符(ASID),ASID唯一标识每个进程,并为进程提供地址空间的保护。

保护

分页情况下的内存保护是通过与每个帧关联的保护位来实现的。用一个位可以定义一个页是可读可写的还是只可读。每次内存引用都要通过页表,来查找正确的帧码。在计算物理地址的同时,可以通过检查保护位来验证与没有对只读页进行操作。
还有一个位通常与页表中的每一条目相关联:有效-无效位。当该位为有效时,该值表示相关的页在进程的逻辑地址空间内,因此是合法的页。当该位是无效的时候,该值表示先关的页不在进程的逻辑地址空间内。通过使用有效-无效位,非法地址会被捕捉到。
还有一个问题,一个进程很少会使用的它的所有地址空间,如果为地址范围内的所有页都在页表中建立一个条目,这将是非常浪费的。有的系统会提供硬件来解决这个问题,如**页表长度寄存器(PTLR)**来表示页表的大小,该寄存器的值可用于检查每个逻辑地址以验证其是否位于进程的有效范围内。

共享页
分页的优点之一就是可以共享公共代码。
注意:代码必须是可重入代码纯代码才可以共享。可重入代码是不能自我修改的代码,他在执行期间不会改变

页表结构

分层分页

现代操作系统支持大逻辑地址空间,在这种情况下页表本身可以非常的大。比如一个位逻辑地址空间的计算机操作系统。如果系统的页大小为4KB(2122^{12}),那么页表可以多达100万的条目,假设每个条目有4字节,那么每个进程需要4MB物理地址空间来存储页表本身。
常用的解决方法就是分层分页。比如两层分页算法,就是将页表在分页。
在这里插入图片描述
其中p1p_1是用来访问外部页表的索引,p2p_2是内部页表的页偏移,这种方案一般称为向前映射页表
对于64位的架构,分层分页是不适用的,因为每一层的页表分完之后还是太大了。

哈希页表

处理大于32位地址空间的常用方法就是使用哈希页表。采用虚拟页码作为哈希值。哈希页表的每一个条目都包括一个链表,该链表的元素哈希到同一位置(该链表用来解决碰撞)。每个元素由三个字段组成:

  1. 虚拟页码
  2. 映射的帧码
  3. 指向链表内下一个元素的指针

该算法的工作:虚拟地址的虚拟页码哈希到哈希表。用虚拟页码与链表内的第一个元素的第一个字段相匹配。如果匹配,那么相应的帧码就用来形成物理地址;如果不匹配,那么与链表内的后续节点的第一个字段进行比较,以查找匹配的页码。

基于哈希页表的一个变体采用聚簇页表,哈希表中的每个条目引用多个页而不是单个页,因此单个页表条目可以映射到多个物理帧。聚簇页表对于稀疏地址空间特别有用,这里的引用是不连续的并且散步在整个地址空间中。

倒置页表

通常情况下每个进程都有一个页表,该进程使用的每个页都是该页表的一项。但是这种方法的缺点就是会造成每个页表可能包含数以百万记的条目,占用大量的内存。
所以有了倒置页表。对于每个真正的内存页或帧,倒置页表才有一个条目。每个条目包含保存在真正内存位置上的页的虚拟地址以及拥有该页进程的信息。所以在一个系统中只有一个页表,并且每物理内存的页只有一条相应的条目。在这里插入图片描述
由于一倒置页表通常包含多个不同的映射物理内存的地址空间,通常要求它的每个条目保存一个地址空间标识符,用来确保具体进程的每个逻辑页可映射道德相应的物理帧。



参考:《操作系统概念》(第九版)

posted @ 2019-03-30 17:19  如是说  阅读(825)  评论(0编辑  收藏  举报