【问题标题】:High level description of program stages程序阶段的高级描述
【发布时间】:2010-10-15 22:37:56
【问题描述】:

我试图对程序生命周期中从源代码到执行的不同阶段进行高级描述。


积分:

  1. 预处理:在此阶段处理宏、包含文件和编译器指令。
  2. 编译:源文件编译成obj文件
  3. 链接器:不同的 obj 文件链接到单个可执行文件。在这个阶段,虚拟地址被分配给可执行文件中的函数、变量和数据。对于 32 位机器,每个进程有 4GB 的地址空间。 1-2 GB 是为操作系统保留的。因此 2-3 GB 的地址空间可以分配给任何进程。
  4. 执行:在程序执行期间,加载程序进入画面。它基本上将程序从虚拟地址空间加载到物理内存地址。所以当进程开始执行时,操作系统会为进程分配内存并调用它的main函数。

问题:

  1. 如果一个程序二进制图像大小为2MB,那么是否必须将完整的二进制图像加载到物理内存中才能执行程序?我的理解是程序必须完全加载到物理内存中才能执行。不可能在具有 256 MB 物理内存的机器上运行大小为 512MB 的程序。只有当程序的内存需求增长时,虚拟内存和分页才有用。

  2. 当程序请求更多内存时,即当它使用 new/malloc 分配堆内存时,内存将保留在虚拟地址空间中。在被引用之前它不会被提交。


如果您觉得我的理解有误,请指出。
有没有什么文章或博客可以给我一两页对整个过程的高级描述?

【问题讨论】:

  • 这不是语言无关的。 Java 没有宏。 Python 几乎不做这些。这是特定于 C 和 C++ 的。
  • 或其他类似编译模型的语言,如FORTRAN、Pascal等

标签: operating-system


【解决方案1】:

1)所以如果一个程序二进制图像大小是 2MB,那么就是完整的二进制 图像必须加载到物理 程序执行的内存?根据我的 理解程序必须是 完全加载到物理内存中 执行。将不可能 运行一个大小为 512MB 的程序 具有 256 MB 物理内存的机器 .只有当内存需求 程序增长然后虚拟内存和 分页很有帮助。

不,大多数(全部?)现代操作系统按需加载页面。如果一个页面没有被使用,它将不会被加载。

2) 当程序要求更多内存时 即当它使用分配堆内存时 new/malloc,然后内存被保留 在虚拟地址空间中。它不会 在被引用之前一直提交。

不一定——运行时可以预先请求一大块并立即提交它,然后分配提交的内存。我不知道实际执行此操作的任何内容,但整个区域都依赖于实现。

【讨论】:

  • 好的,这意味着当程序最初加载到内存中时,它是按照操作系统页面而不是完整的二进制图像加载的?
【解决方案2】:

在数字 4 下,我认为您可能会错过这是从某些物理存储复制程序的位置,例如磁盘或服务器,进入操作系统的内存。这与您所说的不太一样,因为在我看来,物理内存和虚拟内存是操作系统的一部分。

关于第一个疑问,我认为不一定。考虑一下,如果我开始运行一个游戏,它会花费一个初始时间来加载属于同一可执行文件的一部分的文件,因此会运行一些东西来告诉 O/S 加载文件。

【讨论】:

    【解决方案3】:

    在我看来,这并不完全与语言无关,因为许多语言没有与预处理阶段相对应的任何内容。但是,它一开始是相当准确的。

    您似乎将虚拟地址空间与磁盘文件存储混淆了。实际上,它是物理内存的附属物,工作方式相同(性能除外)。它使用磁盘,但与使用文件的方式不同。

    您知道物理内存的工作原理。虚拟内存是一种以通常是透明的方式伪造更大内存的方法。文件被分成“页”,页根据需要从磁盘读入。物理内存被划分为“页框”,物理内存地址与它当前所代表的虚拟地址没有任何关系。显然,如果程序使用的内存超过了物理可用的内存,则必须重用页框,因此必须将页框的内容写回(如果从读取时更改),并加载新的页。

    如果程序一次只使用其地址空间的一部分(“工作集”),并且该部分的页数足够少,因此它们可以同时位于物理内存中,这很好用。如果它不断引用超出物理内存容量的页面,则必须不断从磁盘读取页面(“抖动”),性能急剧下降,并且磁盘处于持续负载状态。

    因此,当我编译和链接一个程序时,磁盘上的文件系统中有一个可执行文件。当我执行它时,它被分配了一个地址空间,然后它变得更加复杂。实际上,它被加载到内存中,多少物理内存和多少虚拟内存与用户无关(除非它没有足够的物理内存,它会运行得非常慢)。

    因此,可以用 256M 的物理内存运行一个 512M 的程序。

    当从堆请求内存时,它被分配到内存位置。至少 C 和 C++ 标准要求它是可用的,除非请求失败,所以“提交”在我看来是一个奇怪的词选择。在使用之前,它不必位于物理内存中。

    【讨论】:

      【解决方案4】:

      第 2 点不完整。编译器生成组装成二进制文件的程序集。

      第 3 点是错误的。内核虚拟内存空间保留与链接器无关。内核空间取决于操作系统。在 Windows 中,它甚至是可配置的(臭名昭著的 /3GB 开关)。

      第 4 点是错误的。可执行映像映射到虚拟内存。它本身实际上并没有“加载”。

      你的问题的答案:

      1. 程序映射到虚拟内存,而不是物理内存。然后,虚拟内存管理器 (VMM) 负责确保内存在需要时位于物理内存中。
      2. new/alloc 请求堆内存。堆是对虚拟内存的抽象,以最小化内存分配可能产生的内核切换量。如果堆太小而不能满足分配请求,堆就会增长,导致虚拟内存分配。由堆管理器决定是否提交页面。

      【讨论】:

      • 第 3 点:当链接器创建二进制可执行文件时,图像中的函数、数据、变量分配了哪些地址。我认为它们是虚拟地址。
      • 第 3 点:即使我们有 /3GB 开关,windows 中的应用程序也不会使用 3GB 地址空间,除非明确指定。链接器有一个开关可以告诉应用程序使用 3GB 地址空间。
      • 链接器只是要告诉提及数据在哪里是相对的,然后将开关添加到操作系统的 PE 标头。但是映射到虚拟空间是操作系统的工作,链接器只是将二进制文件组装成一个文件:可执行文件。
      • 即使使用启动开关,二进制文件也无法获得 3GB 的原因是出于效率和复古兼容性的原因。但实际上 3GB 的东西是一个 hack。它还设置了一个用于 DLL 的虚拟转换表,这些 DLL 可能加载到与请求不同的虚拟地址。
      【解决方案5】:

      DLL 和可执行文件是使用内存映射文件加载的,因此它们实际上并未复制到 RAM,它们仍在磁盘上,只是将它们的字节映射到进程的虚拟地址空间。

      【讨论】:

        猜你喜欢
        • 2014-07-20
        • 2015-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多