“Any problem in computer science can be solved by another layer of indirection.

——程序员的自我修养

物理寻址

早期,CPU在处理某个进程的时候,处理的流程如下。

物理寻址方式

对于物理寻址而言,我们需要直接将程序全部装入到物理内存中,接下来运行期间,CPU在处理时,直接进行物理寻址。然后执行相关的读写命令。

对于物理内存而言,是不做任何访问限制的,所以直接操作进行物理寻址会导致一个问题是:

  1. 读写内存的安全性问题

    1. 不同的进程被分配到不同的物理内存中,运行期间导致进程A错误修改了进程B占用的物理内存,导致进程B出现问题
    2. 危害操作系统自身的安全。恶意的进程直接修改操作系统所占用的物理空间,导致系统崩溃
  2. 内存的利用率不高

    1. 一个系统中,不同的进程是共享CPU和物理内存资源的,如果有很多的进程需要很大的内存,那么就会导致这些进程所需的内存大小 > 实际的物理内存,这样就会导致有些有些进程无法被执行。

所以,为了更加有效的管理内存并且少出错,现代的操作系统提供了一种对主存的抽象概念—-虚拟内存虚拟内存是硬件异常、硬件地址翻译、主存、磁盘和内核软件的完美交互

虚拟内存概念

虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
现代所有用于一般应用的操作系统都对普通的应用程序使用虚拟内存技术,老一些的操作系统,如DOS和1980年代的Windows,或者那些1960年代的大型机,一般都没有虚拟内存的功能
——维基百科

image-20210726164801304

引入序中所引用的话Any problem in computer science can be solved by another layer of indirection. 同理虚拟内存为进程<--->物理内存的中间层,它为进程隐藏了物理内存的概念,同时为其提供了更加简洁易用的接口,供其调用。同时还提供了一些更加复杂的功能。

能力一:高速缓存

我们可以将虚拟内存看作是磁盘上的一片空间,当这片空间中的一部分访问比较频繁时,该部分数据会以页为单位被缓存到主存中以加速 CPU 访问数据的性能,虚拟内存利用空间较大的磁盘存储作为『内存』并使用主存储缓存进行加速,让进程认为操作系统的内存很大而且很快,然而区域很大的磁盘并不快,而很快的内存也并不大

虚拟内存作为缓存
虚拟内存作为缓存

在虚拟内存中的虚拟页共分为三种类型:

  1. 未分配
    1. 没有被进程申请使用的,也就是空闲的虚拟内存, 不占用虚拟内存磁盘的任何空间
  2. 未缓存
    1. 仅仅加载到磁盘中的页
  3. 已缓存
    1. 已经加载到内存中的内存页(页框)

能力二:内存管理

  • 简化链接和加载

  • 简化内存共享

    将不同的进程中的页表中某些页表项映射到相同的物理地址,即可实现内存的共享。

  • 简化内存分配

    独立的虚拟内存空间也会简化内存的分配过程,当用户程序向操作系统申请堆内存时,操作系统可以分配几个连续的虚拟页,但是这些虚拟页可以对应到物理内存中不连续的页中。

能力三:内存保护

现代操作系统中,用户进程不应该被允许修改它的只读代码段,而且也不应该允许它读取或修改任何内核中的代码和数据结构,并且也不允许其读取或者修改其他进程的私有内存,以及修改和其他进程共享的虚拟页面。如果不对进程的内存访问进行限制,攻击者就能够访问和修改其他进程的私有内存,进而导致整个系统崩溃。

通过虚拟内存,我们为进程提供了独立的地址空间,同时这也让我们能够快速的区分不同进程的私有内存。同时我们通过虚拟内存到实际的物理内存的转化需要使用地址翻译机制,整体流程如下所示:

虚拟寻址方式
虚拟寻址方式

通过MMU,每次都会读取页表中的一个页表条目(PTE),通过在这些页表条目(PTE)中添加一些标志位,就能够实现对一个虚拟页的访问控制权限。譬如:

带标志位的页表
带标志位的页表

应用程序如何如何使用和管理虚拟内存

  • [ ] TODO

总结

虚拟内存的思想,整体来看就是:通过结合磁盘和内存各自的优势,利用中间层对资源进行更合理地调度,充分提高资源的利用率。并提供和谐以及统一的抽象。个人目前接触到的最直观的体现就是 JDK中集合类的设计与实现。其也可以算是数据和数据结构之间的中间层,结合其他的技术譬如泛型,为上层的数据提供了接口的同时,隐藏了内部数据结构的实现以及维护。

最后再总结下为什么需要虚拟内存:

  • 虚拟内存可以结合磁盘和物理内存的优势为进程提供看起来速度足够快并且容量足够大的存储;
  • 虚拟内存可以为进程提供独立的内存空间并引入多层的页表结构将虚拟内存翻译成物理内存,进程之间可以共享物理内存减少开销,也能简化程序的链接、装载以及内存分配过程;
  • 虚拟内存可以控制进程对物理内存的访问,隔离不同进程的访问权限,提高系统的安全性;

references