虚拟内存它在现代操作系统中扮演的关键角色,计算机是复杂的机器,旨在执行简单的任务:运行程序(浏览器,文本编辑器,Web 服务器,视频游戏等),这些程序对数据(照片,音乐,文本文件,数据库等)进行操作。

当不使用这些程序和数据时,这些程序和数据可以在硬盘驱动器中安静地运行,即使您的计算机已关闭,该设备也可以使信息保持活动状态。运行应用程序意味着要求处理器(也称为中央处理单元或 CPU)读取并执行构成计算机程序的机器指令以及任何其他数据处理。

硬盘驱动器存储大量信息,但速度却非常慢。比处理器慢得多:直接从硬盘读取指令的 CPU 将成为整个系统的严重瓶颈。因此,程序及其数据首先被复制到主存储器(又称随机存取存储器或 RAM),这是另一个比硬盘驱动器小但速度更快的存储硬件组件,因此处理器可以从那里读取指令而不会造成速度损失。

主存储器可以看做是一长串的单元格,每个单元格包含一些二进制数据,并标有一个称为存储器地址的数字。内存地址范围从 0 到 N,具体取决于系统中可用的主内存量。程序使用的地址范围称为地址空间。

VM动态资源分配架构图 虚拟机动态内存_虚拟地址

 

1、早期计算机中主内存的使用

在计算机历史的开端(以及现在在嵌入式系统中 ( https://en.wikipedia.org/wiki/Embedded_system )),程序可以访问整个主存储器,并且其管理权交给程序员。为这些机器编写软件具有挑战性:开发人员的工作之一是设计一种管理 RAM 访问的好方法,并确保整个程序不会溢出可用的内存。

当多个程序可以在同一台计算机上运行时,随着多任务处理 ( https://www.internalpointers.com/post/gentle-introduction-multithreading )的出现,事情变得更加棘手。程序员必须面对新的关键问题:

  1. 内存布局: 在第一个程序之后位于 RAM 中的程序将使它们的地址空间偏移一定的量,不再在初始范围 0 到 N 范围内;
  2. 内存碎片化 ( https://en.wikipedia.org/wiki/Fragmentation_%28computing%29 ): 随着事物在内存中来回移动,可用空间被碎片化为越来越小的块。这将使得更难找到可用空间来将新程序和数据加载到内存中;
  3. 安全性: 如果程序 A 意外覆盖了程序 B 的内存该怎么办?或更糟糕的是:如果它故意从另一个程序中读取敏感数据,例如密码或信用卡信息,该怎么办?

因此,对于 1960 年代初期的硬件架构师而言,一种自动内存管理的形式可以极大地简化编程, 并解决更为关键的内存保护问题,这一点非常明显。最终他们提出了今天所说的虚拟内存。

 

2、简而言之, 虚拟内存

在虚拟内存中,程序无法直接访问物理 RAM。而是与虚假的地址空间(称为虚拟地址空间)交互。操作系统与处理器一起工作以提供这种虚拟地址空间,并将其迟早转换为物理地址空间。

每个内存访问都是通过虚拟地址执行的,该虚拟地址不引用内存中的实际物理位置。程序总是读取或写入虚拟地址,并且完全不知道底层硬件中发生了什么。

VM动态资源分配架构图 虚拟机动态内存_虚拟内存_02

 

3、虚拟内存的好处

在上面的图片中,您可以看到一个虚拟的到物理的转换示例,它揭示了虚拟内存的两个主要优点:

  1. 每个程序都有一个从 0 开始的虚拟地址空间-这大大简化了程序员的工作:不再需要手动跟踪内存偏移;
  2. 即使底层物理物理内存不是连续的,虚拟内存也始终是连续的-操作系统辛苦地将可用内存块收集到一个统一的虚拟内存块中。

虚拟内存机制还解决了 RAM 受限的问题:每个进程都给人一种印象,即它正在使用不确定的内存量,通常大于物理内存。此外,虚拟内存可确保安全性:程序 A 在不触发操作系统错误的情况下不能读写分配给程序 B 的虚拟内存。在下面的段落中,我们将看到如何实现所有这些魔术。

 

4、页和框架: 一切开始的地方

虚拟内存机制需要一个位置来存储虚拟地址和物理地址之间的映射。也就是说,给定虚拟地址 X,系统必须能够找到相应的物理地址 Y。但是,您无法将信息保存为 1:1 关系:它将需要与整个 RAM 一样大的数据库!

现代虚拟内存实现通过将虚拟内存和物理内存解释为一长串固定大小的小块,从而克服了这个问题(以及许多其他问题)。虚拟内存的块称为页,物理存储器的块称为帧。该存储器管理单元(MMU)是在 CPU 中的一种硬件组件称为一个特殊的数据结构内页和帧之间存储的映射信息的页表。页表就像数据库表,其中的每一行都包含页索引及其对应的框架索引。如下图所示,每个正在运行的程序在 MMU 中都有一个页表。

VM动态资源分配架构图 虚拟机动态内存_物理内存_03

 

5、将页面转换为框架

虚拟地址由两部分组成:

  1. 一个页索引,告诉虚拟地址所属的页;
  2. 一个帧偏移,告诉框架内的物理地址的位置。

该信息足以使 MMU 执行虚拟到物理的转换。当程序读取或写入虚拟地址时,它将唤醒 MMU,该 MMU 依次获取页索引(1),并在程序的页表中搜索相应的帧。一旦找到帧,MMU 就会利用帧偏移量(2)来查找确切的物理内存地址,并将其传递回程序。至此,转换完成:程序在 RAM 中有一个物理地址,可以通过虚拟地址进行读写。

 

6、在虚拟内存的幕后

尽管为程序提供了连续,整洁的虚拟地址空间,但是操作系统和硬件都可以通过驻留在物理内存中的数据在后台执行疯狂的操作。

例如,操作系统通常会延迟从硬盘驱动器加载程序的某些部分,直到该程序尝试使用它为止。有些代码将仅在初始化期间或发生特殊情况时运行。程序的页表中可能会填充指向不存在或尚未分配的帧的条目。上面的图片 3.描绘了这种情况,其中最后两页映射到任何地方。

这样的技巧对应用程序是完全透明的,该应用程序在不了解背景噪音的情况下继续读写自己的虚拟地址空间。但是,该程序迟早可能要访问未映射到 RAM 的虚拟地址之一:该怎么办?

 

7、页错误

一个page fault(也称为page miss,程序当前未映射到一个物理帧的网页上访问虚拟地址时发生)。更具体地说,当页存在于程序的页表中但指向物理内存中不存在或尚不可用的帧时,就会发生页错误。

MMU 检测到页错误并将消息重定向到操作系统,操作系统将尽最大努力在物理内存中找到用于映射的帧。在大多数情况下,这是一个简单的操作,除非系统用完 RAM。

   

8、分页或物理内存不足时

分页是另一种内存管理技巧:当没有可用的物理内存时,操作系统会将一些页移到硬盘上,以便在没有更多可用物理内存时为其他程序或数据腾出空间。有时也叫交换,虽然不是 100%正确。交换是将整个过程移动到磁盘上。有些操作系统在需要时也会这样做。

Paging给程序带来了无限数量的可用 RAM 的幻觉。操作系统乐观地允许虚拟内存地址空间大于物理地址空间,因为知道在需要时可以将数据移入或移出硬盘驱动器。为此,某些系统(例如 Windows)使用称为分页文件的特殊文件。其他(例如 Linux)具有专用的硬盘分区,称为交换区(swap area)(尽管出于历史原因,现代 Linux 执行分页而不是交换)。

不幸的是,硬盘驱动器比主存储器要慢得多。因此,当发生页错误并将页面临时移至硬盘驱动器时,操作系统必须从缓慢的介质中读取数据并将其移回到内存中,从而导致延迟。总而言之,更少的分页意味着系统可以更高效地运行。

 

 9、中断

当系统在页调度中花费的时间比正在运行的应用程序花费的时间多时,就会发生中断,这是由持续不断的页错误流触发的。如果您正在运行太多的程序以填满整个 RAM 和/或未优化硬盘上的页面区域,则会发生这种极端情况。操作系统试图满足大量的页错误请求,不断在硬盘驱动器和物理内存之间移动数据,使系统停止运行。可以通过增加 RAM 数量,减少正在运行的程序数量或通过调整交换文件的大小来避免颠簸。

 

10、内存保护

虚拟内存还为运行中的应用程序提供了安全性:浏览器无法窥探文本编辑器的虚拟内存,反之亦然,而不会触发错误。内存保护的主要目的是防止进程访问不属于它的内存。

内存保护机制通常由 MMU 及其管理的页表提供,而其他体系结构则可能使用不同的硬件策略。当程序尝试访问它不拥有的部分虚拟内存时,将触发无效的页错误。MMU 和操作系统捕获信号,并引发称为分段错误(在 Unix 上)或访问冲突(在 Windows 上)的故障情况。作为响应,操作系统通常会终止程序。

分段错误和访问冲突也常常是由于错误引起的。执行手动内存管理的编程语言使您能够留出一部分内存来存储程序数据:操作系统将为您提供不错的空闲内存块(也称为缓冲区),以便根据您的读写程序的需求。但是,没有什么可以阻止您在缓冲区边界之外进行读取或写入,访问不属于您的程序或根本不存在的内存。操作系统将检测到非法访问并发出通常的违规信号。

 

11、更多

虚拟内存为许多其他有趣的话题铺平了道路。例如, ( https://en.wikipedia.org/wiki/Memory-mapped_file )是对读写文件的传统方式的强大抽象。内存映射允许程序直接从硬盘驱动器访问文件,而不是将数据手动复制到内存中以对其进行操作,就好像该文件已经完全加载到 RAM 中一样。必要时,虚拟内存机制将照常将数据从硬盘驱动器移至 RAM。内存映射文件简化了程序员的工作,通常可以加速文件访问操作。更多信息在这里 ( https://stackoverflow.com/questions/192527/what-are-the-advantages-of-memory-mapped-files )。

虚拟内存也使推理内存消耗变得更加困难。假设您的程序之一占用了 300 MB 的内存:它是虚拟的还是物理的?该空间的一部分是否已分页到磁盘?如果是的话,分页操作是否足够快?同样,如果您想使系统保持良好状态,则调整分页文件/交换分区是重要的一步。操作系统提供了许多测量和调整内存的工具:此处 ( https://superuser.com/questions/437918/how-do-i-find-whats-eating-up-all-of-my-systems-memory-not-superfetch )和此处提供 ( https://www.linux.com/training-tutorials/5-commands-checking-memory-usage-linux/ )更多信息。

英文原文: http://suo.im/5E6ONl