【问题标题】:What exactly is the JIT compiler inside a JVM?JVM 中的 JIT 编译器到底是什么?
【发布时间】:2017-05-20 17:56:29
【问题描述】:

我试图了解 Java 源代码是如何执行的,但我对 JVM 中的 JIT 编译器实际上是什么感到困惑。首先,让我告诉你我如何理解从 Java 源代码到在计算机上执行机器代码的过程。也许,我在导致混乱的过程中误解了一些东西。

步骤:

  1. 源代码编译成字节码(.class文件)
  2. 类文件被加载到 JVM(在 RAM 中)
  3. 字节码经过验证,然后由 JIT 编译器处理
  4. JIT 编译器的输出是准备好执行的机器代码

现在,根据Wikipedia article on JVM,更具体地说,“字节码解释器和即时编译器”部分,为了执行 Java 字节码,您需要一个 解释器(但我们有JIT 编译器)。

现在让我感到困惑的是。我把它分解成引号:

“当解释器执行 Java 字节码时,执行速度总是比编译成本机机器语言的相同程序的执行速度慢。”

  1. 既然计算机只能执行机器码,而解释器将字节码翻译成机器码的速度比编译器慢,为什么 JVM 使用解释器而不是编译器?

  2. 为什么我们没有另一个由 JIT 编译器为 CPU 生成的中间可执行文件,以便它可以快速执行指令?

“JIT 编译器可以在执行程序时将 Java 字节码翻译成本地机器语言。程序的翻译部分可以比它们被解释的速度更快地执行。这种技术被应用于这些部分一个经常执行的程序。”

JIT 编译器真的是一个能够编译频繁执行的代码的解释器吗?编译器和解释器这两个术语是否被错误地互换使用?

提前致谢。

【问题讨论】:

  • “JIT Compller”这个词已经过时了。它指的是 1.3 之前的 JVM 插件架构,它在执行之前编译所有字节码。发现“JIT 编译器到处喷洒代码”,这导致了我们现在所拥有的,称为“HotSpot”,它选择性地根据其执行历史编译字节码。根据您的 Wikipedia 引文,目前的趋势是使用“JIT”来指代两者,但实际上这只是令人困惑,而且在历史上也不准确。
  • @EJP 感谢您的回复。当您说它指的是两者时,您是指编译器和解释器吗?所以如果我理解正确的话,起初JVM内部的翻译器是一个编译器,但由于安全问题被替换了。这意味着在 1.3 之前,从源代码到机器代码的整个翻译过程有 2 个单独的编译步骤。一个从源代码到字节码,另一个从字节码到机器码。目前,翻译器更像是逐行执行代码的解释器,偶尔充当常用代码的编译器。对吗?
  • 我想知道的另一件事是机器代码究竟是如何到达 CPU 的。我假设当代码逐行处理时,解释器只是传递该机器代码。不那么明显的是,当您有一个包含机器代码的中间文件时,CPU 如何获取机器代码。编译器是否从文件中提供 CPU 指令?
  • 我的意思是,您引用的 Wikipedia 文章将 JIT 编译器和 HotSpot JVM 称为同一个东西,它们不是一个国家英里。我试图编辑它一次,但思想警察反对。 1990 年代后期的情况是 JIT DLL 由第三方(例如 Symantec)提供,并通过 JVM 的命令行选项启用,这顺便回答了您上面的另一个问题,而 HotSpot内置在 JVM 中,并通过命令行选项禁用。在 JIT 或 HotSpot 下没有包含机器代码的中间文件。

标签: java jvm


【解决方案1】:

既然计算机只能执行机器码,而解释器将字节码翻译成机器码的速度比编译器慢,为什么 JVM 使用解释器而不是编译器?

因为编译成机器码也需要时间,尤其是当它必须分析代码以优化它时,所以解释速度足以在大多数情况下执行,而且如果只运行一次/偶尔运行,实际上比编译+运行要快。

此外,解释器不会“将字节码翻译成机器码”。它评估字节码并执行字节码请求的操作。解释器本身是机器码,但它不翻译字节码,它解释/评估字节码。

为什么我们没有另一个由 JIT 编译器为 CPU 生成的中间可执行文件,以便它可以快速执行指令?

这将违反 Java 的一次编写,随处运行的范例。

JIT 编译器真的是能够编译频繁执行的代码的解释器吗?

不,JIT 编译器(或更准确地说,HotSpot 编译器,如mentioned by EJP)是 JVM 根据需要执行的编译器。

编译器和解释器这两个术语是否被错误地互换使用?

正确。它们不能互换使用,因为它们不做同样的事情。解释器执行字节码。 JIT/HotSpot 编译器将字节码转换为机器码,但不运行它。

【讨论】:

  • 嗯,好的!根据您和 CoronA 的回答,似乎每次处理和执行某些源代码时,都会在某个阶段涉及解释器。简而言之,需要解释,但不需要编译。我猜在编译语言中,解释步骤是显式的(如 Java 的情况)而在解释语言中是隐式的。
  • 另外,你为什么说拥有第二个编译代码的中间文件会违反“一次编写,随处运行”范式?事实上,我认为这就是 Java 与字节码编译一起工作的方式。正如您所说,JIT 编译器将字节码转换为机器码,然后由解释器执行,因此还有另一个中间步骤。由于 Java 解释器是特定于机器的,而 Java 字节码不是,因此任何 Java 解释器都可以解释字节码。这意味着您可以编写一次程序并在任何地方运行它,不是吗?也许我没有正确说出我的问题 2
  • @ribarcheto94 嗯.. 不... 1) 不需要解释。甚至对于字节码也不行。 JVM 可以选择将所有内容编译为机器码,在这种情况下不会进行任何解释。 2) 编译为机器代码的语言(例如 C、C++)不会以任何方式被解释。 3)也许你没有说对,因为你说“为什么我们没有另一个中间可执行文件”,而我们不编译成机器码,因为我们希望我们的输出可以在任何地方运行。 JVM 做什么完全取决于 it我们 不在乎,只要 it 做好它的工作。
  • 哈哈!如果不需要解释,为什么 JVM 上的维基百科文章会这样说:“对于每种硬件架构,都需要不同的 Java 字节码解释器。当计算机具有 Java 字节码解释器时,它可以运行任何 Java 字节码程序,而同一个程序可以可以在任何具有这种解释器的计算机上运行。”根据您上面的评论,解释器似乎只是机器代码指令的包装器,对吗?如果编译语言不需要解释,编译后的代码如何执行?
  • @ribarcheto94 因为他们选择不将所有内容编译成机器码,所以需要一个解释器来运行未编译的代码。如果 JVM 实现选择 将所有内容编译为机器码,那么 那个 实现将不需要解释器。这完全取决于实施。有一个解释器不是强制性的,但是我认为没有任何实现可以以这种方式工作。这并不意味着不可能。 --- 结束我在#1中所说的重复。
【解决方案2】:

由于计算机只能执行机器码,而解释器 将字节码转换为机器码的速度比编译器慢 就是,为什么JVM使用的是解释器而不是编译器?

优化编译是一个非常持久的过程。而且只有在程序运行时间更长的情况下,这笔费用才合理。

在错误的地方进行优化是不必要的。一段只遍历一次的代码,编译时间会比解释时间多,所以解释是ok的。

如果代码的某些部分被频繁处理,编译器会更好地处理这两个主题。

为什么我们没有另一个中间可执行文件生成 CPU 的 JIT 编译器,因此它可以快速执行 说明?

这个“文件”(编译后的片段)确实存在于内存中。它没有被序列化为文件,因为:

  • 这样的文件在很大程度上依赖于操作系统和硬件
  • 某些代码优化只能在运行时应用,例如JIT 编译器可以优化虚拟调用(通过跳转甚至内联代码替换动态调度)

JIT 编译器真的是能够编译 > 频繁执行的代码的解释器吗?术语编译器和解释器 错误地互换使用?

虽然 JVM Hotspot 编译器会编译频繁执行的代码,但其他 JIT 编译器可能会根据其他启发式方法决定进行编译。术语“JIT 编译器”和“解释器”没有明显区别。大多数解释器都进行了优化(及时编译),几乎每个 JIT 编译器都会进行解释。

【讨论】:

  • '持久'是一个糟糕的描述。相对于运行应用程序的 JVM 而言,它并不持久。
  • 这是关于优化提前编译的一般性声明。整个部分应该解释即时编译的好处,而不是提前编译。因此,如果我们就事实达成一致,我可以将帖子编辑得更简洁。
猜你喜欢
  • 1970-01-01
  • 2020-06-20
  • 2010-12-31
  • 2016-05-24
  • 2017-06-09
  • 2011-05-01
  • 1970-01-01
  • 2011-02-23
  • 2023-03-06
相关资源
最近更新 更多