深入理解计算机系统——知识总结(二)

第 7 章

7.1 编译器驱动程序

7.2 静态链接

7.3 目标文件

7.4 可重定位目标文件

7.5 符号和符号表

7.6 符号解析

7.7 重定位

7.8 可执行目标文件

7.9 加载可执行目标文件

7.10 动态链接共享库

7.11 从应用程序中加载和链接共享库

7.12 位置无关代码

7.13 库打桩机制

7.14 处理目标文件的工具

----------------------------------先写第九章的内容-------------------------------------

第九章

  • 为了更加有效地管理内存并且少出错,现代系统提供了一种对主存的抽象概念,叫做虚拟内存(VM)。虚拟内存是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的和私有的地址空间。通过一个很清晰的机制,虚拟内存提供了三个重要的能力:1)它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效地使用了主存。2)它为每个进程提供了一致的地址空间,从而简化了内存管理。3)它保护了每个进程的地址空间不被其他进程破坏。
  • 虚拟内存是核心的。虚拟内存遍及计算机系统的所有层面,在硬件异常、汇编器、链接器、加载器、共享对象、文件和进程的设计中扮演着重要角色。
  • 虚拟内存是强大的。虚拟内存给予应用程序强大的能力,可以创建和销毁内存片(chunk)、将内存片映射到磁盘文件的某个部分,以及与其他进程共享内存。
  • 虚拟内存是危险的。每次应用程序引用一个变量、间接引用一个指针,或者调用一个诸如malloc这样的动态分配程序时,它就会和虚拟内存发生交互。如果虚拟内存使用不当,应用将遇到复杂危险的与内存有关的错误。例如,一个带有错误指针的程序可以立即崩溃于“段错误”或者“保护错误”,它可能在崩溃之前还默默地运行了几个小时,或者是最令人惊慌地,运行完成却产生不正确的结果。

9.1 物理和虚拟寻址

深入理解计算机系统——知识总结(二)_第1张图片

  • 计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组。每字节都有一个唯一的物理地址(Physical Address,PA)。第一个字节的地址为0,接下来的字节地址为1,再下一个为2,依此类推。给定这种简单的结构,CPU访问内存的最自然的方式就是使用物理地址。我们把这种方式称为物理寻址(physical addressing)。图9-1展示了一个物理寻址的示例,该示例的上下文是一条加载指令,它读取从物理地址4处开始的4字节字。当CPU执行这条加载指令时,会生成一个有效物理地址,通过内存总线,把它传递给主存。主存取出从物理地址4处开始的4字节字,并将它返回给CPU,CPU会将它存放在一个寄存器里。
  • 现代处理器使用的是一种称为虚拟寻址(virtual addressing)的寻址形式,参见图9-2。
    深入理解计算机系统——知识总结(二)_第2张图片
  • 使用虚拟寻址,CPU通过生成一个虚拟地址(Virtual Address,VA)来访问主存,这个虚拟地址在被送到内存之前先转换成适当的物理地址。将一个虚拟地址转换为物理地址的任务叫做地址翻译(address translation)。就像异常处理一样,地址翻译需要CPU硬件和操作系统之间的紧密合作。CPU芯片上叫做内存管理单元(Memory Management Unit,MMU)的专用硬件,利用存放在主存中的查询表来动态翻译虚拟地址,该表的内容由操作系统管理。

9.2 地址空间

  • 地址空间(address space)是一个非负整数地址的有序集合:
    在这里插入图片描述
  • 如果地址空间中的整数是连续的,那么我们说它是一个线性地址空间(linear address space)。为了简化讨论,我们总是假设使用的是线性地址空间。在一个带虚拟内存的系统中,CPU从一个有N=2n个地址的地址空间中生成虚拟地址,这个地址空间称为虚拟地址空间(virtual address space)
    在这里插入图片描述
  • 一个地址空间的大小是由表示最大地址所需要的位数来描述的。例如,一个包含N=2n个地址的虚拟地址空间就叫做一个n位地址空间。现代系统通常支持32位或者64位虚拟地址空间。
  • 一个系统还有一个物理地址空间(physical address space),对应于系统中物理内存的M个字节:
    在这里插入图片描述
  • M不要求是2的幕,但是为了简化讨论,我们假设M=2m
  • 地址空间的概念是很重要的,因为它清楚地区分了数据对象(字节)和它们的属性(地址)。一旦认识到了这种区别,那么我们就可以将其推广,允许每个数据对象有多个独立的地址,其中每个地址都选自一个不同的地址空间。这就是虚拟内存的基本思想。主存中的每字节都有一个选自虚拟地址空间的虚拟地址和一个选自物理地址空间的物理地址。

9.3 虚拟内存作为缓存的工具

  • 缓存在主存中。和存储器层次结构中其他缓存一样,磁盘(较低层)上的数据被分割成块,这些块作为磁盘和主存(较高层)之间的传输单元。VM系统通过将虚拟内存分割为称为虚拟页(Virtual Page,VP)的大小固定的块来处理这个问题。每个虚拟页的大小为P=2p字节。类似地,物理内存被分割为物理页(Physical Page,PP),大小也为P字节(物理页也被称为页帧(page frame))。
    在任意时刻,虚拟页面的集合都分为三个不相交的子集:
    ● 未分配的:VM系统还未分配(或者创建)的页。未分配的块没有任何数据和它们相关联,因此也就不占用任何磁盘空间。
    ● 缓存的:当前已缓存在物理内存中的已分配页。
    ● 未缓存的:未缓存在物理内存中的已分配页。
    图9-3的示例展示了一个有8个虚拟页的小虚拟内存。虚拟页0和3还没有被分配,因此在磁盘上还不存在。虚拟页1、4和6被缓存在物理内存中。页2、5和7已经被分配了,但是还未缓存在主存中。
    深入理解计算机系统——知识总结(二)_第3张图片

9.3.1 DRAM缓存的组织结构

  • 为了有助于清晰理解存储层次结构中不同的缓存概念,我们将使用术语SRAM缓存来表示位于CPU和主存之间的L1、L2和L3高速缓存,并且用术语DRAM缓存来表示虚拟内存系统的缓存,它在主存中缓存虚拟页。DRAM比SRAM要慢大约10倍,而磁盘要比DRAM慢大约100000多倍。因此,DRAM缓存中的不命中比起SRAM缓存中的不命中要昂贵得多,这是因为DRAM缓存不命中要由磁盘来服务,而SRAM缓存不命中通常是由基于DRAM的主存来服务的。
  • DRAM缓存的组织结构完全是由巨大的不命中开销驱动的。因为大的不命中处罚和访问第一个字节的开销,虚拟页往往很大,通常是4KB~2MB。由于大的不命中处罚,DRAM缓存是全相联的,即任何虚拟页都可以放置在任何的物理页中。不命中时的替换策略也很重要,因为替换错了虚拟页的处罚也非常之高。因此,与硬件对SRAM缓存相比,操作系统对DRAM缓存使用了更复杂精密的替换算法。最后,因为对磁盘的访问时间很长,DRAM缓存总是使用写回,而不是直写。

9.3.2 页表

  • 同任何缓存一样,虚拟内存系统必须有某种方法来判定一个虚拟页是否缓存在DRAM中的某个地方。如果是,系统还必须确定这个虚拟页存放在哪个物理页中。如果不命中,系统必须判断这个虚拟页存放在磁盘的哪个位置,在物理内存中选择一个牺牲页,并将虚拟页从磁盘复制到DRAM中,替换这个牺牲页。
  • 这些功能是由软硬件联合提供的,包括操作系统软件、MMU(内存管理单元)中的地址翻译硬件和一个存放在物理内存中叫做页表(page table)的数据结构,页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换为物理地址时,都会读取页表。操作系统负责维护页表的内容,以及在磁盘与DRAM之间来回传送页。
  • 图9-4展示了一个页表的基本组织结构。页表就是一个页表条目(Page Table Entry,PTE)的数组。虚拟地址空间中的每个页在页表中一个固定偏移量处都有一个PTE。假设每个PTE是由一个有效位(valid bit)和一个n位地址字段组成的。有效位表明了该虚拟页当前是否被缓存在DRAM中。
  • 图9-4中的示例展示了一个有8个虚拟页和4个物理页的系统的页表。四个虚拟页(VP1、VP2、VP4和VP7)当前被缓存在DRAM中。两个页(VP 0和VP5)还未被分配,而剩下的页(VP3和VP6)已经被分配了,但是当前还未被缓存。图中还有一个点要注意,因为DRAM缓存是全相连的,所以任意物理页都可以包含任意虚拟页。
    深入理解计算机系统——知识总结(二)_第4张图片

9.3.3 页命中

  • 考虑一下当CPU想要读包含在VP2中的虚拟内存的一个字时会发生什么(图9-5),VP 2被缓存在DRAM中。使用我们将在9.6节中详细描述的一种技术,地址翻译硬件将虚拟地址作为一个索引来定位PTE2,并从内存中读取它。因为设置了有效位,那么地址翻译硬件就知道VP2是缓存在内存中的了。所以它使用PTE中的物理内存地址(该地址指向PP1中缓存页的起始位置),构造出这个字的物理地址。
    深入理解计算机系统——知识总结(二)_第5张图片

9.3.4 缺页

  • 在虚拟内存的习惯说法中,DRAM缓存不命中称为缺页(page fault)。图9-6展示了在缺页之前我们的示例页表的状态。CPU引用了VP3中的一个字,VP3并未缓存在DRAM中。地址翻译硬件从内存中读取PTE3,从有效位推断出VP3未被缓存,并且触发一个缺页异常。缺页异常调用内核中的缺页异常处理程序,该程序会选择一个牺牲页,在此例中就是存放在PP3中的VP4。如果VP4已经被修改了,那么内核就会将它复制回磁盘。无论哪种情况,内核都会修改VP4的页表条目,反映出VP4不再缓存在主存中这一事实。
    深入理解计算机系统——知识总结(二)_第6张图片
  • 接下来,内核从磁盘复制VP3到内存中的PP3,更新PTE3,随后返回。当异常处理程序返回时,它会重新启动导致缺页的指令,该指令会把导致缺页的虚拟地址重发送到地址翻译硬件。但是现在,VP3已经缓存在主存中了,那么页命中也能由地址翻译硬件正常处理了。图9-7展示了在缺页之后我们的示例页表的状态。
    深入理解计算机系统——知识总结(二)_第7张图片

9.3.5 分配页面

  • 图9-8展示了当操作系统分配一个新的虚拟内存页时对我们示例页表的影响,例如,调用malloc的结果。在这个示例中,VP5的分配过程是在磁盘上创建空间并更新PTE5,使它指向磁盘上这个新创建的页面。
    深入理解计算机系统——知识总结(二)_第8张图片

9.3.6 又是局部性救了我们

  • 虚拟内存 工作得相当好,这主要归功于我们的老朋友局部性(locality)。
  • 尽管在整个运行过程中程序引用的不同页面的总数可能超出物理内存总的大小,但是局部性原则保证了在任意时刻,程序将趋向于在一个较小的活动页面(active page)集合上工作,这个集合叫做工作集(working set)或者常驻集合(resident set)。在初始开销,也就是将工作集页面调度到内存中之后,接下来对这个工作集的引用将导致命中,而不会产生额外的磁盘流量。
  • 只要我们的程序有好的时间局部性,虚拟内存系统就能工作得相当好。但是,当然不是所有的程序都能展现良好的时间局部性。如果工作集的大小超出了物理内存的大小,那么程序将产生一种不幸的状态,叫做抖动(thrashing),这时页面将不断地换进换出。虽然虚拟内存通常是有效的,但是如果一个程序性能慢得像爬一样,那么聪明的程序员会考虑是不是发生了抖动。
  • 注:可以利用Linux的getrusage函数监测缺页的数量

9.4 虚拟内存作为内存管理的工具

  • 到目前为止,我们都假设有一个单独的页表,将一个虚拟地址空间映射到物理地址空间。实际上,操作系统为每个进程提供了一个独立的页表,因而也就是一个独立的虚拟地址空间。图9-9展示了基本思想。在这个示例中,进程i的页表将VP1映射到PP2,VP2映射到PP7。相似地,进程j的页表将VP1映射到PP7,VP2映射到PP10。注意,多个虚拟页面可以映射到同一个共享物理页面上。
    深入理解计算机系统——知识总结(二)_第9张图片
  • VM简化了链接和加载、代码和数据共享,以及应用程序的内存分配。
    • 简化链接
      独立的地址空间允许每个进程的内存映像使用相同的基本格式,而不管代码和数据实际存放在物理内存的何处
    • 简化加载
      虚拟内存还使得容易向内存中加载可执行文件和共享对象文件。
    • 简化共享
      独立地址空间为操作系统提供了一个管理用户进程和操作系统自身之间共享的一致机制。
    • 简化内存分配
      虚拟内存为向用户进程提供一个简单的分配额外内存的机制。(如调用malloc的结果)

9.5 虚拟内存作为内存保护的工具

  • 任何现代计算机系统必须为操作系统提供手段来控制对内存系统的访问。不应该允许一个用户进程修改它的只读代码段。而且也不应该允许它读或修改任何内核中的代码和数据结构。不应该允许它读或者写其他进程的私有内存,并且不允许它修改任何与其他进程共享的虚拟页面,除非所有的共享者都显式地允许它这么做(通过调用明确的进程间通信系统调用)。
  • 就像我们所看到的,提供独立的地址空间使得区分不同进程的私有内存变得容易。但是,地址翻译机制可以以一种自然的方式扩展到提供更好的访问控制。因为每次CPU生成一个地址时,地址翻译硬件都会读一个PTE,所以通过在PTE上添加一些额外的许可位来控制对一个虚拟页面内容的访问十分简单。图9-10展示了大致的思想。
    深入理解计算机系统——知识总结(二)_第10张图片
  • 在这个示例中,每个PTE中已经添加了三个许可位。SUP位表示进程是否必须运行在内核(超级用户)模式下才能访问该页。运行在内核模式中的进程可以访问任何页面,但是运行在用户模式中的进程只允许访问那些SUP为0的页面。READ位和WRITE位控制对页面的读和写访问。例如,如果进程i运行在用户模式下,那么它有读VP0和读写VP1的权限。然而,不允许它访问VP2。
    如果一条指令违反了这些许可条件,那么CPU就触发一个一般保护故障,将控制传递给一个内核中的异常处理程序。Linux shell一般将这种异常报告为“段错误(segmenta-tion fault)"。

9.6 地址翻译

  • 图9-11概括了我们这节里要使用的所有符号。
    深入理解计算机系统——知识总结(二)_第11张图片
  • 形式上来说,地址翻译是一个N元素的虚拟地址空间(VAS)中的元素和一个M元素的物理地址空间(PAS)中元素之间的映射,
    在这里插入图片描述
  • 这里
    在这里插入图片描述
  • 图9-12展示了MMU如何利用页表来实现这种映射。CPU中的一个控制寄存器,页表基址寄存器(Page Table Base Register,PTBR)指向当前页表。n位的虚拟地址包含两个部分:一个p位的虚拟页面偏移(Virtual Page Offset,VPO)和一个(n-p)位的虚拟页号(Virtual Page Number, VPN)。
    深入理解计算机系统——知识总结(二)_第12张图片

你可能感兴趣的:(笔记,CSAPP,网络,java,开发语言)