【问题标题】:Virtual Address Space虚拟地址空间
【发布时间】:2021-03-18 02:43:01
【问题描述】:

我已经开始了解虚拟地址空间 (VAS),我有几个问题:

  1. 根据架构(32 位和 64 位)为每个进程创建多少 VAS?
  2. 是否在硬盘上为每个进程创建了 VAS?如果是这样,如果没有足够的空间会怎样?
  3. VAS 和虚拟内存 (VM) 有什么区别?

【问题讨论】:

    标签: linux memory-management process virtual-memory virtual-address-space


    【解决方案1】:

    虚拟地址与物理地址

    在程序执行期间,变量(整数、数组、字符串等)存储在计算机主内存中的某个位置 (RAM)。一些编程语言(如 C 或 C++)允许您获取存储给定变量的内存地址(使用 & 运算符),并操作该地址(添加、减去、打印等) .).

    这是一个打印变量内存地址的C程序:

    #include <stdio.h>
    
    int main(void) {
        int variable = 1234;
        void *address = &variable;
        printf("Memory address of variable: %p\n", address);
        return 0;
    }
    

    输出:

    Memory address of variable: 0x7ffc9e9662a4
    

    现在,如果您在具有典型操作系统(如 GNU/Linux 或 Windows)的典型台式计算机上编译和执行此程序,则此程序打印的内存地址不是数据所在的硬件地址1234 实际上位于memory chip。这可能令人惊讶,但程序使用的地址和硬件地址之间存在一定程度的间接性。

    64 位计算机上的虚拟地址空间

    在 64 位计算机上,程序操作的内存地址是介于 0 和 18446744073709551615 之间的整数。这样的地址称为虚拟内存地址。这些地址的范围称为进程的虚拟地址空间。您可以要求操作系统将一系列虚拟内存地址映射到您计算机的物理内存,这样当您尝试在这些地址读取或写入字节时,您的程序就不会崩溃访问未映射的虚拟内存地址。

    通常,在 x86-64 计算机上,only 248 virtual memory addresses 可以成功映射到物理内存,因为 256 TiB 的可用虚拟地址空间被认为是足够的。将来,如果需要,处理器制造商可能会提高或取消此限制。

    32 位计算机上的虚拟地址空间

    在 32 位计算机上,有 232 个虚拟内存地址。在这些计算机上,您的程序操作的内存地址是介于 0 和 4294967295 之间的整数。

    在 x86 32 位计算机上,可以映射到物理内存地址的虚拟内存地址范围通常没有限制。

    映射一系列虚拟内存地址

    在 GNU/Linux 上,您可以通过调用函数 mmap() 来请求映射。在 Windows 上,您可以通过调用函数 VirtualAlloc() 来请求映射。这些函数将映射的大小作为参数,并返回现在由实际物理内存支持的第一个虚拟地址。如果物理内存已被其他进程完全使用,这些函数可能无法创建新映射。同样,如果您尝试访问(读取或写入)位于mmap()VirtualAlloc() 映射的区域之外的虚拟内存地址的内容,操作系统将终止您的程序(通过发送分段错误信号) .

    在 GNU/Linux 上,进程可以通过读取文件 /proc/self/maps 来检查在其虚拟地址空间中创建的映射。通过阅读命令cat /proc/self/maps 的输出,您可以学到很多东西。

    硬盘驱动器

    在典型的计算机上,主内存是semiconductor memoryhard disk drive 只是辅助存储设备。

    在典型的操作系统上,一系列虚拟内存地址只能映射到主内存(通常是半导体存储设备)。如果不使用主存作为中介,这样的范围不能直接映射到辅助存储设备(通常是硬盘驱动器)。

    【讨论】:

    • 为什么操作系统不允许你直接使用硬件地址?
    【解决方案2】:
    1. 在 n 位机器上,VAS 为 2n 个字节。因此,在 32 位机器上,VAS 232 = 4 GiB 大。

    2. 虚拟内存未在磁盘上创建。实际上,实现虚拟内存并不需要磁盘的存在。大多数虚拟内存的实现都是分页的。因此,当创建 4 GiB VAS 时,只有需要的页面才会映射到该 VAS。例如,假设一个进程在 32 位系统上仅使用 16 页内存,页面大小为 4k。尽管有 4 GiB VAS,但只有 16 * 4k = 216 字节的内存被映射到 VAS。其余的内存未映射。如果 CPU 试图访问这个未映射的内存,就会发生分段错误。如果一个进程想要在这个地址映射内存,那么(在一个 POSIX 兼容的操作系统中)它可以使用mmap(2) 从操作系统请求映射。一旦您了解了页表,这将更有意义。

    3. 虚拟内存是一个概念。虚拟地址空间是源于虚拟内存概念的实体。这些术语齐头并进,但指代不同的事物。

    我将列出一些注意事项。

    警告 1.1

    我不知道任何真正支持 64 位 VAS 的 64 位处理器。地址本身是 64 位宽,但一定数量的高位被忽略。 AMD 的第一个 x86_64 实现只支持 48 位地址。地址的高 16 位实际上被忽略了。在这样的系统中,地址为 64 位宽,但 VAS 的实际大小限制为 248 字节。后续架构支持 56 位地址。

    注意事项 1.2

    如果处理器支持PAE,则 n 位机器上的 VAS 可能大于 2n 个字节。这就是 32 位处理器如何支持大于 4 GiB 的 VAS。

    注意事项 2.1

    这并不是一个警告,但这与您的问题有关。您问当磁盘上没有足够的空间来创建 VAS 时会发生什么。正如我在主要答案中提到的,VAS 不是在磁盘上创建的。但是,任何计算机都只有有限数量的物理内存。当进程请求映射页面但没有可用的物理内存时会发生什么?有几种方法可以解决这个问题:

    1. 交换是通过将虚拟内存中映射的页面临时移动到磁盘来完成的。页面的全部内容被复制到磁盘。然后,请求页面的进程将物理页面映射到它们的内存中。最终,可能会请求旧页面。如果发生这种情况,则操作系统会从磁盘复制页面并将其重新映射到相应的 VAS。这就是 Linux 和大多数现代操作系统所做的。
    2. 简单地告诉进程没有可用的内存,例如,通过像 ENOMEM 这样的错误号。
    3. 进程被阻塞,直到内存可用。我没有在实践中看到过这种情况。

    交换意味着使用磁盘,但虚拟内存并不意味着使用交换,因此虚拟内存不需要磁盘。

    【讨论】:

      【解决方案3】:
      1. Virtual Address Space - wikipedia

      在 32 位操作系统上执行新应用程序时,该进程有一个 4 GiB VAS:该空间中的每个内存地址(从 0 到 232 - 1)可以有一个字节作为值。最初,它们都没有值。

      对于 n 位操作系统,这些 n 地址行允许地址空间最多 2n 个地址,即 0 到 2n - 1。这意味着 16 EiB对于 64 位操作系统。 (虽然在实际实现中,使用的空间更少,因为不需要这么多空间。)


      1. CPU Cache - wikipedia

      大多数通用 CPU 都实现了某种形式的虚拟内存。总而言之,机器上运行的每个程序都看到自己的简化地址空间,其中仅包含该程序的代码和数据,或者所有程序都在公共虚拟地址空间中运行。程序通过计算、比较、读取和写入其虚拟地址空间的地址来执行,而不是物理地址空间的地址,从而使程序更简单,因此更容易编写。

      例如,在C++中,程序内存被分为栈、堆、数据、代码。我不确定类比是否正确(可能正确),但如果您知道的话,它在某种程度上提供了一种洞察力。


      1. Virtual memory - wikipedia

      在计算中,虚拟内存是一种内存管理技术,它提供了“给定机器上实际可用的存储资源的理想化抽象”3 “给使用非常大(主)内存的用户带来错觉”。[4]

      计算机的操作系统结合使用硬件和软件,将程序使用的内存地址(称为虚拟地址)映射到计算机内存中的物理地址。在进程或任务看来,主存储表现为连续的地址空间或连续段的集合。操作系统管理虚拟地址空间以及实际内存到虚拟内存的分配。

      CPU 中的地址转换硬件,通常称为内存管理单元 (MMU),自动将 虚拟地址转换为物理地址。操作系统中的软件可以扩展这些功能,以提供一个虚拟地址空间,该地址空间可以超过实际内存的容量,从而引用比计算机中实际存在的内存更多的内存。

      如果您了解计算机体系结构(我相信您从问题中了解),现在就可以澄清了。 不过,对于一般人来说,我给出了一些解释。

      • 在 C++ 中将地址假定为指针。如果您不了解 C++,最接近的类比是任何语言中的数组/列表索引。现在地址指向内存位置,就像指针指向变量一样。实际数据存储在变量中。要使用指针/索引获取变量数据,您需要提供要从中提取数据的地址位置。现在在物理内存中,不会有变量之类的东西。有内存和访问它的位置地址。
      • 真正的内存是物理内存,也就是硬盘。它使用物理地址访问,每个字节都是唯一的。
      • 直接使用物理地址访问物理内存会很麻烦。因此,操作系统将地址简化为虚拟地址。这些地址可能是唯一的,也可能不是唯一的(记住,这些不是物理地址)。因此,多个虚拟地址可能指向同一个位置。
      • 虚拟内存实际上并不存在,它只是一个使用虚拟地址简化的物理内存概念,为用户提供了一个幻觉空间,即下一个内存位置存储在下一个地址(准确地说是虚拟地址)的位置。李>
      • 由于可以使用 MMU 将多个虚拟地址映射到同一个物理地址,从而指向同一个物理内存位置,因此可以使虚拟内存大小超过物理内存大小(虚拟)。但实际上,内存大小仍然与物理大小相同。

      因此,为了访问内存数据,虚拟地址由用户/程序指定给操作系统,由内存管理单元 (mmu) 转换为物理地址,然后应用于计算机体系结构的地址线(电子发现! !),它会在相应的物理位置产生数据。而这个概念被称为虚拟内存。

      -喜满树

      【讨论】:

        猜你喜欢
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-07-03
        • 2020-04-16
        • 2014-12-11
        • 2016-01-13
        • 2012-03-06
        相关资源
        最近更新 更多