在教程中,我遇到了一个新概念(对我而言),我从未想过这是可能的。实际上,我认为编译是一个完全预运行的过程。这是教程中的短语:“编译时间发生在链接时间之前(当一个或多个编译文件的输出连接在一起时)和运行时(执行程序时)。在某些编程语言中,可能需要进行一些编译和编译。链接发生在运行时“。
我的问题是:
非常感谢你的时间!
答案 0 :(得分:1)
我个人都知道的最好(最着名)的例子是Java使用的just in time compilation。您可能知道Java代码正在编译为字节码,可由Java虚拟机解释。因此,它不同于让我们说C ++首先被完全(预处理)编译(并链接)成可执行文件,可以直接由操作系统运行而无需任何虚拟机。
VM字节码由VM解释,它将它们映射到处理器特定指令。据说JVM执行JIT,它接受该字节码并将其(在运行时)编译成机器代码。在这里,我们到达您的第二个问题。即使在Java中,它也可以依赖于您正在使用的JVM,但基本上有一些代码称为热点,这些代码经常运行并且可能被编译以便应用程序的性能提高。这是在运行时期间完成的,因为普通编译器没有(或者很可能没有)所有必要的数据来正确判断哪些代码实际上经常运行。因此,JIT需要某种运行时统计收集,这与程序执行并行完成,由 JVM 完成。收集什么样的统计数据,可以优化什么(在运行时编译)等取决于实现(显然你不能做普通编译器由于内存和时间限制所做的一切 - 猜测这部分回答了第一个问题?您没有编译所有内容,通常在运行时编译中只支持一组有限的优化。你可以尝试寻找这样的信息,但根据我的经验,它通常记录得非常糟糕,很难找到(至少在官方消息来源,而不是演示文稿/博客等)。
Linker是一双不同的鞋子。我们不能再使用Java示例了,因为它没有像C或C ++这样的链接器(而是它有一个类加载器来处理加载文件和放置这一切)。
通常链接是在编译步骤(静态链接)之后由链接器执行的,这有优点(无依赖性)和缺点(更高的内存印记,因为我们不能使用共享库,当库号更改时需要重新编译源)。
运行时链接(动态/后期链接)实际上是由 OS 执行的,并且操作系统链接器的工作是首先加载共享库然后将它们附加到正在运行的处理。此外,还有不同类型的动态链接:显式和隐式。这样做的好处是,当版本号发生变化时不必重新编译源代码,因为它的动态和库共享也有缺点,如果你有不同的程序使用相同的库但需要不同的版本会怎么样(查找 DLL地狱)。所以,这两个概念也完全不同。
它是如何完成的,它是如何决定什么以及如何链接的,是特定于操作系统的,例如微软有dynamic-link library概念。