【问题标题】:How compilation and linking at runtime is happening?运行时的编译和链接是如何发生的?
【发布时间】:2015-07-31 07:35:29
【问题描述】:

在教程中,我遇到了一个新概念(对我而言),这是我从未想过的。实际上,我认为编译是一个完全运行前的过程。这是教程中的短语:“编译时间发生在链接时间(一个或多个编译文件的输出连接在一起时)和运行时(执行程序时)之前。在某些编程语言中,某些编译和链接发生在运行时”。

我的问题是:

  1. 预运行时编译和链接过程是否与运行时编译和链接完全不同?如果是,请说明主要区别。
  2. 如何标记在运行时需要编译(链接)的代码段以及这些信息保存在哪里? (这可能因语言而异,如果可能,请举一个具体的例子)。

非常感谢您的宝贵时间!

【问题讨论】:

    标签: compilation linker runtime


    【解决方案1】:

    运行时编译

    我个人知道的最好的(最知名的)示例是 Java 使用的 just in time compilation。正如您可能知道的那样,Java 代码正在被编译成 Java 虚拟机可以解释的字节码。因此,它与 C++ 不同,后者首先完全(预处理)编译(并链接)成可执行文件,无需任何虚拟机即可由操作系统直接运行。

    Java 字节码由虚拟机解释,虚拟机将它们映射到特定于处理器的指令。话虽如此,JVM 执行 JIT,它获取该字节码并将其(在运行时)编译成机器码。在这里,我们到达您的第二个问题。即使在 Java 中,它也可能取决于您使用的 JVM,但基本上有称为 hotspots 的代码片段,这些代码片段经常运行并且可能会被编译以提高应用程序的性能。这是在运行时完成的,因为普通编译器没有(或者很可能没有)所有必要的数据来正确判断哪些代码实际上经常运行。因此,JIT 需要某种运行时统计收集,它与程序执行并行完成,由 JVM 完成。收集什么样的统计数据,可以优化什么(在运行时编译)等取决于实现(由于内存和时间限制,您显然无法完成普通编译器所做的一切 - 猜想这部分回答了 第一个问题?您不会编译所有内容,并且通常在运行时编译中只支持一组有限的优化)。您可以尝试查找此类信息,但根据我的经验,它的文档通常非常糟糕且很难找到(至少在涉及官方资源时,而不是演示文稿/博客等)

    运行时链接

    Linker 是一双不同的鞋子。我们不能再使用 Java 示例了,因为它实际上并没有像 C 或 C++ 那样的 linker(相反,它有一个 classloader 负责加载文件并将其全部放入一起)。

    通常链接是在编译步骤(静态链接)之后由链接器执行的,这有优点(无依赖关系)和缺点(更高的内存印记,因为我们不能使用共享库,当库编号发生变化时,您需要重新编译您的来源)。

    运行时链接(动态/后期链接)实际上是由操作系统执行的,操作系统链接器的工作是首先加载共享库,然后将它们附加到正在运行的进程。此外,还有不同类型的动态链接:显式和隐式。这样做的好处是当版本号更改时不必重新编译源代码,因为它是动态的和库共享,但也有缺点,如果您有不同的程序使用相同的库但需要不同的版本(查找 DLL hell)。所以是的,这两个概念也完全不同。

    这一切又是如何完成的,如何决定应该链接什么以及如何链接,是特定于操作系统的,例如 Microsoft 有 dynamic-link library 概念。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 2016-08-18
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多