操作系统之内存超载(交换和虚拟内存)

若计算机的物理内存足够大,那么可以保存所有进程。但实际上,所有进程所需要的RAM数量总和通常远超存储器所支持的范围。面对内存超载问题,操作系统有两种通用方法,一是交换,把一个进程完整调入内存,使该进程运行一段时间,然后把他存回磁盘,空闲进程主要存储在磁盘上,当他们不运作时也就不会占用内存。另一种策略是虚拟内存,该策略能使程序在只有一部分被调入内存的情况下运行。

交换

交换系统的操作如下图所示
在这里插入图片描述
阴影部分为未使用内存,在程序运行时A首先被调入磁盘,在最后又被调入内存。交换在内存中会产生众多空间区,通过把所有进程向下移动可以将小空闲区合并成大块,这种技术称为内存紧缩,其本质也是一个复制的过程,将数据内存中数据大批量移动复制相应也会消耗大量CPU时间。

交换在分配内存有一个注意思考的问题,在进程创建或者调入时应该为其分配内存。若是对于大小不变的进程分配原则很简单,操作系统按照其需要的大小进行分配。但是现在很多程序设计语言都允许用户从堆上动态分配内存,那么当进程空间试图增长是,又该如何分配内存呢?一种可行的方法是当换入或者移动进程时额外分配一些内存,将分配的内存分为进程所需大小和增长预留大小空间两部分。值得注意的是当进程被调出此内存时需要交换的是进程实际大小,否则将额外的内存交换会产生浪费。
对于此类结构的设计可以参考下图
在这里插入图片描述
堆中存放程序员动态申请的变量,栈中存放普通局部变量和返回地址,程序堆栈段在进程所占的内存的顶端向下增长,紧接着程序段后面的数据段向上增长。两者之间的内存供两个段使用。当这一段空间被用完,进程必须移动到足够大的空闲区或者被交换出内存等待拥有足够的内存区再被置入或者结束该进程。

对于动态分配的内存,操作系统需要对其进行管理。主要方法为位示图法和空闲链表法,在linux中会使用一些特定的内存分配器,如伙伴分配器和slab分配器。

虚拟内存

虚拟内存基本思想:每个程序拥有自己的地址空间,这个空间会被分割成多个块,每一块称为一个页或页面。每一页有连续的地址空间。这些页被映射到物理内存,但不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立即执行必要的映射。当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的指令。

在任何一台计算机上,程序引用了一组内存地址。地址可以通过索引、基地址寄存器、段寄存器及其他方式产生。这些地址称为虚拟地址,它们构成一个虚拟地址空间。在没有虚拟地址的计算机上,系统直接将虚拟地址运送到内存总线上,读写操作使用具有相同地址的物理内存字;若在使用虚拟内存的情况下,虚拟地址不是被送到内存总线上,而是被送到内存管理单元MMU上,并通过MMU把虚拟地址映射到物理地址上。

在这里插入图片描述
假设有一台16位地址的计算机,地址范围从0-64K-1,这些地址为虚拟地址。然而这台计算机只有32KB的物理内存,因此无法将编写的64KB的程序完全调入内存。虚拟地址空间按照固定大小被划分成页面,在物理内存中对应的单元成为页框。本题中页面和页框大小为4KB。

若此时程序试图访问地址0,执行如下指令
MOV REG 20500
此时虚拟地址20500被送到MMU,MMU发现虚拟地址20500在页面5上,根据映射结果,这一页面对应页框3,而虚拟地址20在距虚拟页面5起始地址20字节处,即偏移量为20。所以最终MMU将虚拟地址转换为12288+20=12308物理地址。通过恰当设置MMU,可以把16个虚拟页面映射到8个页框中去,但是还有8个页面没有被映射。在实际的硬件中,有一个标记位记录页面是否在内存中。

若此时访问一个未在内存中的页面会发生什么情况呢?MMU注意到该页面没有被映射,于是使CPU陷入到操作系统,这个陷阱称为缺页中断。这时操作系统会使用页面置换算法,选择一个很少使用的页框,把它的内容写到磁盘(如果不在磁盘上)。随后把需要访问的页面读到刚刚回收的页框中,修改映射关系吗,然后重新启动引起陷阱的指令。

对于虚拟内存到物理内存的的映射关系,我们可以用页表来描述。虚拟地址可以被分配虚拟页号和页内偏移量。例如,对于16位地址和4KB的页面大小,其高四位为虚拟页号,低12位为页内偏移量。虚拟页号可用作页表的索引,找到该虚拟页面对应的页表项。由页表项可以找到对应内存中的页框号。然后把页框号+页内偏移量得到最终的物理地址。

页表项结构

在这里插入图片描述

在任何分页系统中需要考虑如下两个问题:
1、虚拟地址到物理地址的映射必须非常快。
2、如果虚拟地址很大,页表也会很大。
对于问题一,我们发现大多程序总是对少量的页面进行多次访问,因此只有很少的页表项会被反复读取,所以我们设置一个小型硬件设备,将虚拟地址直接映射成物理地址而非通过访问页表,这种设备称为转换检测缓冲区快表
对于问题二,处理巨大的虚拟地址空间,采用两种方法。一是采用多级页表的方式;二是采用倒排页表。

当发生缺页中断时,操作系统必须在内存中选择一个页面调出,为调入的页面腾出足够空间。若患处的页面在内存停驻期间被修改过,那就要把它重新写回磁盘,若没有被修改过,则不需要写回。直接用调入页面覆盖被淘汰的页面即可。

缺页中断处理需要经过保护中断现场、分析中断原因、转入中断处理程序、恢复中断现场等步骤。具体流程如图。
在这里插入图片描述

在页面置换选择时,页面置换算法尤为重要。

  1. FIFO先进先出页面置换算法
  2. LRU最近最少使用页面置换算法:发生页面中断时,置换未使用时间最长的页面。很难实现,因为在内存中需要一个链表去维护,把最近最多使用的页面放在表头,最少使用的放在表尾,每次访问内存时必须更新整个链表。
  3. 最佳置换算法
  4. 简单clock算法: 为每一页设置一个访问位,再将所有的页面通过链接指针组成一个循环队列,当某一页被访问时,其访问位被置1,置换算法在选择淘汰页面的时候只需要检查个页面的访问位。如果为一则将改页访问位置零,不换出。如果为0则将该页作为淘汰页换出。
  5. 改良clock算法

最后总结下虚拟内存优缺点

优点

  1. 扩大内存地址空间。
  2. 内存保护,每个进程运行在各自的虚拟内存空间,互不干扰。虚拟内存还对特定的内存地址提供写保护,防止代码或者数据篡改。
  3. 公平分配内存,每个进程相当于有相同大小的虚拟内存空间。
  4. 当进程通信时可以采用虚拟共享的方式。
  5. 当不同进程需要使用相同的代码时,物理内存中可以只存储一份这样的代码,不同的进程只需要把自己的虚拟内存映射进去就行了。
  6. 在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间而不需要实际物理内存的连续空间,可以利用内存空间碎片。

缺点

  1. 虚拟内存需要建立很多数据结构,占用额外内存。
  2. 虚拟地址到物理地址的映射增加了指令执行时间。
  3. 页面的的置换需要磁盘I/O,十分消耗时间。
  4. 如果一页中只有部分数据,则会浪费内存。

猜你喜欢

转载自blog.csdn.net/GGGGG1233/article/details/114828127
今日推荐