现代操作系统:内存管理(四)

4.3 Virtual Memory(meaning Fetch on Demand)虚拟内存(按需获取)

其思想是允许程序即使只有其活动的地址空间不问保留在内存中它也可以运行,也就是说换入和换出的一部分程序,即使程序的某些部分(也许是大部分)不在内存中,该程序也可以运行

粗略的说,这可以称之为自动覆盖。

优势

  • 系统可以运行一个大于物理内存总量的程序,即进程的虚拟内存大小可以超过计算机的物理内存大小;
  • 即使每个程序都小于物理内存,所有正在运行的程序的内存总和也可能超过物理内存。如果整个程序必须驻留在内存中才能运行,那么就需要某种交换机制。相反,我们将只在内存中保留经常使用的页面,并非在非驻留页面被引用时按需获取;
  • 按需获取的操作可能会增加多道程序的级别,因为活动的程序(已经被加载的程序)的总内存大小可能大于实际的物理内存大小;
  • 由于程序的某些部分很少被使用,所以总是加载它们是一种低效的内存使用方式。如果这些部分没有被使用,按需获取的分页将不会加载它们,与此同时,如果某个部分长时间未被使用,我们则希望卸载它们以支持其余有用的部分。

劣势

  • 提升了操作系统的复杂程度;
  • 执行时间难以预测;
  • 会过度使用内存;

 

The Memory Management Unit and Virtual to Physical Address Translation MMU和虚拟内存向物理内存的转换

内存管理单元(MMU)是处理器中的一块硬件,它与操作系统一起负责将虚拟地址(程序中的地址)转换为物理地址(内存中的真实硬件地址)。

MMU和虚拟地址到物理地址转换的想法同样适用于非需求分页,在过去,分页和虚拟内存的含义也包括这种情况。遗憾的是,在你们老师看来,分页和虚拟内存的现代用法仅限于按需获取的内存系统,通常是某种形式的请求分页。

 

4.3.1 **PagingDemand Paging)按需分页

其思想是在页面被引用时从磁盘获取页面到内存,希望得到内存中使用最频繁的页面,页面大小的设置将在下面讨论。尽管需求分页很复杂,但是它非常常见。实际上,现在已经使用了更加复杂的变体,即多级需求分页和分段分页的需求分页,前者在现代操作系统中占主导地位。

如果页面被加载,每个PTE中仍然会保存对应的页框号,但是如果页面并没有被加载(也就是页面存在于磁盘上),该怎么办?

PTE上有一个标志用于标识页面是否已经被加载(您可以将下图中右侧的X视为设置该标识)如果页面没有加载,磁盘上的位置可以保存在PTE中,但是我们现在并不这样做,而是保存在其他的地方。当对未加载的页面(有时被称之为不存在的页面,但这是一个不好的名字)进行引用时,系统有很多工作要做:

  1. 选择一个空的页框;
  2. 问题:如果没有空的页框怎么办?回答:没有机会就创造机会!选择一个可怜的受害者(这是一个我们将会在后面讨论的替换Replacement问题);如果这个页框是Dirty(被修改过)的话就将页框中的内容写入磁盘;更新受害者页框对应的PTE将其中的内容修改为未被加载(X);现在我们就有了一个闲置页框;
  3. 将需要引用页面从磁盘中拷贝到空页框中;
  4. 更新当前页面对应的PTE,将PTE中的值修改为已被加载并设置对应的页框号;
  5. 然后执行正常的虚拟地址向物理地址的转换;

确实不是这样做的,稍后我们将在讨论页面错误守护进程时看到。

Homework 25

14. A machine has a 32-bit address space and an 8-KB page. The page table is entirely in hardware, with one 32-bit word per entry. When a process starts, the page table is copied to the hardware from memory, at one word every 100 nsec. If each process runs for 100 msec (including the time to load the page table), what fraction of the CPU time is devoted to loading the page tables?

一台机器拥有32-bit的地址空间和一个8KB的页面,页表完全在硬件中,页表的每一表项大小为32-bit。进程启动时,以每个字100ns的速度将页表从内存复制到硬件中,如果每个进程运行100ms(包含装入页表的时间),用来装入页表的CPU时间的比例是多少?

32-bit的地址空间表明内存大小为 ,一个页面8KB说明一个页面的大小为 ,因此页表中包含了 个PTE,每个PTE需要100ns,因此全部复制完毕需要52428800ns = 52428.8us = 52.4288ms。进程全部运行完成使用了100ms,因此装入页表的CPU时间比例为52.4288%。

 

Dirty vs. Clean Frames脏页框和干净的页框

当一个页面从磁盘复制到内存中时,这两个页面会具有相同的内容。如果页面随后被程序读取,那么页面和页框仍然具有相同的内容。但是如果一个页面被程序写入了一定字节的数据,那么此时我们会有两个选择:

  1. 我们可以更新页框中的内容让页框中的内容和页面中的内容一致,此时页框中的内容是Clean的;(我个人的理解是将页框中的内容和磁盘中的页面同步,因为本质上我们是直接操作内存中的内容)。
  2. 我们可以选择不更新页框中的内容,那么这个时候页框和页面中的内容变得不一致,因此此时页框中的内容是Dirty的;

 

4.3.2 Page Tables页表

对页表的讨论同样可应用于非需求分页,但是对于按需分页而言页表的存在是更重要的,有以下两个原因:

  1. 对于按需分页而言,一个很重要的流程是选择一个需要被移除页框的页面,页表中存储的数据会有助于指导我们选择这个受害者;
  2. 活动进程的内存总大小不再受到物理内存大小的限制,由于进程的总大小更大,所以页表的总大小也更大,因此对页表大小的关注也更加重要;

我们必须能够非常快的访问页表,因为每次内存访问都需要访问页表。

 

不幸的硬件法则

  • 根本不存在又大又快的硬件,也就是大和快两者是不兼容的;
  • 规模大、速度快且成本低的方案是不现实的;

所以我们并不能简单的通过把页表放在快速寄存器中实现对页表的快速访问,因为快速寄存器非常贵,这样操作的话以1000美元出售一个这种系统是不现实的。因此最简单便宜的方式仍然是将页表存放在主内存中,如下图所示,但是这种方式似乎既很慢,占用空间也大。

  1. 上述的解决方案看起来实在是太慢了,因为每次对内存进行引用都需要执行一次跳转,也就是先访问页表然后访问实际的物理内存。我们很快就会感受到OS是如何使用TLB这个玩意很大程度上消除中间的一层跳转的;
  2. 这个解决方案看上去实在是太大了:目前我们考虑的是连续的虚拟地址范围(虚拟地址中没有空洞);在这种情况下页表的大小并不是问题,因为PTE的数量等于页面的数量,一个4B-8B的PTE可以对应4KB-8KB大小的页框,空间消耗大约0.1%,所以并不在乎。但是在现代编程语言中通常将堆栈存放在虚拟地址空间的一段,数据段存放在另一端并让它们相对生长;中间的虚拟内存通常是未使用的且对应的空间非常大;但是又显而易见,谁在乎被浪费的虚拟内存呢?
  3. 由于未使用的虚拟内存同样会占用页表的空间,那么实际上存储那么多没有用的PTE是没有必要的,在很多情况下浪费0.1%的内存也是可以优化的;当最大虚拟地址大小与总物理地址大小相当时,该方案运行良好,但是在现在的计算机中,这种方案已经不再有效;解决这个问题的方式是使用多级映射:多级页表和段页式内存管理。

Structure of a Page Table Entry PTE的结构

每个页面都有一个与之对应的页面条目(PTE),PTE中的信息由硬件使用,其格式与具体的机器有关,因此访问PTE的OS进程是不可移植的。操作系统设置和使用的信息通常保存在其他操作系统表中。

页表由页码进行索引,显而易见,页码不会存储在PTE中,但是以下字段会存储在PTE中:

  1. 页框号Frame Number:这个字段必须要有,需要这个玩意将虚拟地址映射到物理地址中去,它是页表中用于非需求分页的唯一字段;
  2. 有效位Valid Bit:这表明一个页面是否正在加载(即在一个页框中),如果有效位被设置则表明页面已经在内存中,并且PTE的页框号是有效的。有效位也被称为存在位或存在/缺席位。如果访问的页面的有效位未设置,CPU会Trap至内核态,这个Trap称之为缺页中断或缺页错误(Page Fault
  3. 修改位或脏位Modify Bit / Dirty Bit:指示页面中的某些部分在加载后已经被写入,当页面被逐出页框时需要判断该位的状态,如果当前页面的内容被修改则需要将页框中的内容写回磁盘,否则不需要。
  4. 引用位或已使用位Referenced or Used Bit:只是页面中的某个字已被引用,它用于选择被逐出的受害者,如果一个页面没有在最近被使用,那么它会是一个很好的受害者;
  5. 保护位Protected Bit例如可以将文本页面标记为仅执行,这要求具有不同保护区域之间的边界在页面边界上。通常许多连续的(逻辑地址)页具有相同的保护。因此许多页保护位是多余的。分段的保护会更加自然,但在许多当前系统中,它是通过分页来完成的,因为许多系统不再使用分段。

Question: Why not store the disk addresses of non-resident pages in the PTE?

回答:在绝大多数系统中,只有在TLB中无法找到时才会进入PTE查找对应的页框号。因此PTE的格式是由硬件决定的,其中只包含了页面命中时需要的一些信息。因此,磁盘地址(用于缺页错误)不存在。

 

4.3.3 Speeding Up Paging加速分页

如上所述,将整个页表单独存储在中央内存中的简单方案似乎既太慢又太大。我们在这里解决了这两个问题,但请注意,后面将讨论关于大小问题的第二种解决方案(分段)。

Translation Lookaside Buffers (and General Associative Memory) 转换检测缓冲区(和相联存储器)

注:Tanenbaum认为相联存储器转换检测缓冲区是同义词,这是错误的,相联存储器是一个通用的概念,其中转换检测缓冲区是一个具体的例子。

相联存储器是一种内容可寻址存储器。也就是说,通过给定某个字段(称为索引)的值来访问内存,硬件搜索所有的记录,并返回其索引字段包含请求值的记录。

举个例子:

如果索引字段是Animal并且给出了Iguana,则关联内存返回(一取一行):

Select * from table where animal = ‘Iguana’;

Izzy  | Iguana | Quiet    | Brown

注意,与页表的情况不同,页号会存储在TLB中,实际上,它是索引字段。TLB既小又贵,但至少速度快。当页号在TLB中时,帧号会很快返回。在失败时,执行TLB重载。页码在页表中查找。找到的记录被放置在TLB中,一个受害者被丢弃(不是真正丢弃,脏的和引用的位被复制回PTE)。由于所有TLB条目都是一次性访问的,因此不存在放置问题,但还有一个替代问题。‘

Homework 26

22. 如果计算机的进程的地址空间中有1024个页,那么它的页表就会保存在内存中。从页表中读取一个单词所需的开销是5 nsec。为了减少这种开销,计算机有一个TLB,它包含32(虚拟页、物理页帧)对,可以在1 nsec内进行查找。需要多大的命中率才能将平均开销降低到2 nsec?

 

posted on 2022-01-06 15:49  ThomasZhong  阅读(145)  评论(0编辑  收藏  举报

导航