乐趣区

关于golang:读书笔记深入操作系统虚拟内存上

为什么须要虚拟内存

运行一个程序, 须要将程序装入内存中, 程序中拜访的内存地址就是物理地址。而且必须保障程序用到的内存总量小于理论物理机的总量。当运行多个程序的时候, 须要为程序调配多个内存

某台计算机总的内存大小是 128M,当初同时运行两个程序 A 和 B,A 需占用内存 10M,B 需占用内存 110。计算机在给程序分配内存时会采取这样的办法:先将内存中的前 10M 调配给程序 A,接着再从内存中残余的 118M 中划分出 110M 调配给程序 B。这种调配办法能够保障程序 A 和程序 B 都能运行,然而这种简略的内存调配策略问题很多
存在的问题如下:

  1. 过程地址空间不隔离,A 过程能够随便拜访 B 过程的数据, 也能随便批改 B 过程的数据
  2. 内存使用率低, 如果又创立了 C 过程, 并且 C 大于操作系统残余的 8MB 内存, 此时须要在 A,B 过程中抉择将一个程序临时拷入磁盘, 腾出空间供 C 应用
  3. 程序运行地址不确定, 调配的地址是随机的
虚拟内存

操作系统应用了 分页 (page) 的形式, 将零碎内存按 page 的形式调配虚拟内存, 个别的操作系统目前每个 page 是 4kb,按这种抉择,4GB 虚拟地址空间共能够分成 1048576 个页,512M 的物理内存能够分为 131072 个页。显然虚拟空间的页数要比物理空间的页数多得多。分页的思维是程序运行时用到哪页就为哪页分配内存,没用到的页临时保留在硬盘上。当用到这些页时再在物理地址空间中为这些页分配内存,而后建设虚拟地址空间中的页和刚调配的物理内存页间的映射。

分页思维的根本了解

上面通过介绍一个可执行文件的装载过程来阐明分页机制的实现办法。一个可执行文件 (PE 文件) 其实就是一些编译链接好的数据和指令的汇合,它也会被分成很多页,在 PE 文件执行的过程中,它往内存中装载的单位就是页。当一个 PE 文件被执行时,操作系统会先为该程序创立一个 4GB 的过程虚拟地址空间。后面介绍过,虚拟地址空间只是一个中间层而已,它的性能是利用一种映射机制将虚拟地址空间映射到物理地址空间,所以,创立 4GB 虚拟地址空间其实并不是要 真的创立空间,只是要创立那种映射机制所须要的数据结构而已,这种数据结构就是页目和页表。

当创立完虚拟地址空间所须要的数据结构后,过程开始读取 PE 文件的第一页。在 PE 文件的第一页蕴含了 PE 文件头和段表等信息,过程依据文件头和段表等信息,将 PE 文件中所有的段一一映射到虚拟地址空间中相应的页(PE 文件中的段的长度都是页长的整数倍)。这时 PE 文件的真正指令和数据还没有被装入内存中,操作系统只是依据 PE 文件的头部等信息建设了 PE 文件和过程虚拟地址空间中页的映射关系而已。当 CPU 要拜访程序中用到的某个虚拟地址时,当 CPU 发现该地址并没有相相关联的物理地址时,CPU 认为该虚拟地址所在的页面是个空页面,CPU 会认为这是个页谬误(Page Fault),CPU 也就晓得了操作系统还未给该 PE 页面分配内存,CPU 会将控制权交还给操作系统。操作系统于是为该 PE 页面在物理空间中调配一个页面,而后再将这个物理页面与虚拟空间中的虚构页面映射起来,而后将控制权再还给过程,过程从方才产生页谬误的地位从新开始执行。因为此时已为 PE 文件的那个页面调配了内存,所以就不会产生页谬误了。随着程序的执行,页谬误会一直地产生,操作系统也会为过程调配相应的物理页面来满足过程执行的需要。

分页办法的核心思想就是当可执行文件执行到第 x 页时,就为第 x 页调配一个内存页 y,而后再将这个内存页增加到过程虚拟地址空间的映射表中, 这个映射表就相当于一个 y =f(x)函数。应用程序通过这个映射表就能够拜访到 x 页关联的 y 页了

虚拟内存的实现

虚拟内存被组织为一个由寄存在磁盘上的 N 个间断的字节大小的单元组成的数组. 每个字节都有惟一的虚拟地址, 作为到数组的索引

在任意工夫, 虚构页面的汇合都分为三个不相交的子集

  1. 未调配的
  2. 缓存的
  3. 未缓存的
页表(page table)

页面将虚构页映射到物理页. 每次地址翻译硬件将一个虚拟地址转化为物理地址时, 都会读取一个页表

图中的 PTE((Page Table Entry,PTE)页面标目数组, 每个 PTE 由 一个无效 位(valid bit)和一个地址组成,无效位表明了该虚构页以后是否存在于物理内存中,如果无效位是 1,该 PTE 中就会存储物理内存中相应的物理页的起始地址。如果无效位是 0,且 PTE 中的地址为 null,这示意这个虚构页还未被调配,而如果无效位是 0 且 PTE 中有地址,那么这个地址指向该虚构页在磁盘上的起始地位

页命中和页异样

  1. 当读取 PTE2, 因为设置了无效位, 地址翻译就晓得 pv2 是缓存再内存中的, 即是页命中
  2. 如果读出 PTE3, 从内存中取出 PTE3, 从无效位推断并未被缓存, 并且不在内存中, 触发一个页异样, 缺页异样会调用内核中的缺页异样处理程序, 就义一个页. 如果 vp4 曾经被批改, 那么内核将它复制到磁盘。不再缓存到主存中. 从磁盘复制 VP3 到内存 PP3, 更新 PET3, 随后返回

局部性原理: 如果不命中的话, 始终都会触发页异样, 页面的调度会相当慢. 局部性原理保障了任意时刻, 程序将趋势一个较小的汇合工作

虚拟内存的作用

  1. 简化链接, 独立的过程空间容许每个过程的内存映像应用雷同的根本格局, 而不必管代码和数据寄存在内存的何处
  2. 简化加载, 虚拟内存使得更容易向内存中加载可执行文件和共享对象文件
  3. 简化共享
  4. 简化内存调配 为用户过程提供一个简略的调配额定内存的机制. 当一个过程须要额定的堆空间时候, 操作系统调配一个适当 k 个间断虚拟内存页面, 并且将他们映射到物理内存中的 k 个工作物理页面

爱护机制

通过在 PTE 下面增加一个额定的标识位来达到爱护权限

TLB
  1. MMU: 将虚拟地址翻译为物理地址, 由硬件实现

每次 MMU 必须查阅一个 PTE,以便在虚拟地址转化为物理地址. 因为在 MMU 中蕴含了一个对于 PTE 的缓存

多级页表

1. 相似树的构造, 应用多级构造

以上就是虚拟内存的基础知识

参考文章

  1. https://zhuanlan.zhihu.com/p/…
  2. https://www.cnblogs.com/logo-…

参考视频

  1. CMU 传授的视频教程 – Lecture17:虚拟内存概念
  2. CMU 传授的视频教程 – Lecture18:虚拟内存零碎
退出移动版