即时 (JIT) 编译器有啥作用?

Posted

技术标签:

【中文标题】即时 (JIT) 编译器有啥作用?【英文标题】:What does a just-in-time (JIT) compiler do?即时 (JIT) 编译器有什么作用? 【发布时间】:2010-09-10 20:55:46 【问题描述】:

与非 JIT 编译器相比,JIT 编译器具体做什么?谁能给个简洁易懂的描述?

【问题讨论】:

ibm.com/support/knowledgecenter/SSYKE2_7.1.0/… Updated Link 我发现youtube.com/watch?v=yQ27DjKnxwo 很有用。 【参考方案1】:

JIT 编译器程序启动后运行,并将代码(通常是字节码或某种 VM 指令)即时(或称为即时)编译成通常更快的形式,通常是主机 CPU 的本机指令集。 JIT 可以访问动态运行时信息,而标准编译器则不能,并且可以进行更好的优化,例如经常使用的内联函数。

这与将所有代码编译为机器语言程序首次运行的传统编译器形成对比。

换句话说,传统编译器在您第一次运行之前将整个程序构建为一个 EXE 文件。对于较新样式的程序,使用伪代码(p-code)生成程序集。只有在您在操作系统上执行程序之后(例如,通过双击其图标),(JIT)编译器才会启动并生成基于 Intel 的处理器或任何可以理解的机器代码(m-code)。

【讨论】:

与解释代码相比,它会立即开始运行字节码或 VM 指令而不会延迟,但运行指令的速度会比机器语言慢。 JIT 通常与解释代码一起使用以将其转换为机器语言,但是是的,纯解释代码(没有任何 JIT 处理)很慢。即使是没有 JITter 的 Java 字节码也很慢。 不过,目标不必是机器码。 JRuby 有一个 JIT 编译器,它会在几次调用后将 Ruby 源代码编译为 Java 字节码。然后,在另外几次调用之后,JVM JIT 编译器启动并将字节码编译为本机代码。 值得注意的是,正如 Jörg 所暗示的,JIT 不一定会立即调用。通常,代码将被解释,直到确定它值得 JITting。由于 JITting 会引入延迟,因此如果某些代码很少使用,则 NOT JIT 可能会更快,因此快速响应比整体运行时更重要。 @ErikReppen:如果新机器问世,使用传统编译器为新机器编译和优化程序可能会比 JIT 更快地产生结果。另一方面,针对该新机器优化的 JIT 将能够优化代码的性能在该新机器发明之前发布【参考方案2】:

一开始,编译器负责将高级语言(定义为比汇编程序更高级别)转换为目标代码(机器指令),然后将其链接(通过链接器)成为可执行文件。

在语言发展的某个阶段,编译器会将高级语言编译成伪代码,然后(由解释器)对其进行解释以运行您的程序。这消除了目标代码和可执行文件,并允许这些语言移植到多个操作系统和硬件平台。 Pascal(编译成 P-Code)是最早的之一; Java 和 C# 是最近的例子。最终,术语 P-Code 被字节码取代,因为大多数伪操作都是一个字节长。

即时 (JIT) 编译器是运行时解释器的一项功能,它不会在每次调用方法时都解释字节码,而是将字节码编译成正在运行的机器的机器代码指令,并且然后调用此目标代码。理想情况下,运行目标代码的效率将克服每次运行时重新编译程序的低效率。

【讨论】:

但是这句话“即时 (JIT) 编译器是运行时解释器的一个特性” 会引起混淆;例如- ***.com/questions/16439512/… 其实 JIT 是一个附加组件,你仍然可以使用 Java 的 -Xint 参数禁用它,所以它只是一个特性。 我不完全同意。 JIT 不是进化——它是经典编译器的替代品。 JIT 是从硬接线机械开关到通过对智能手机说“OK Google”来指定搜索条件的进化路径上的一步。当前作为 Java 7/8 的一部分可用的 JIT 比作为 Java 2 的一部分可用的 JIT 有了飞跃——这也是进化。 @i486 - Sun / Oracle (AFAIK) 从未发布过用于生成本机代码的经典(“提前”)Java 编译器。争辩说 JIT 是一种替代方案是一种延伸……当他们认为它是一种替代方案时,从未发货。 (我对 GCJ AOT 编译器不屑一顾,因为那与 Sun / Oracle 无关,而且它也不是一个完整的解决方案。它现在肯定不可行。)【参考方案3】:

JIT-及时 这个词本身说明何时需要(按需)

典型场景:

源代码完全转化为机器码

JIT 场景:

源代码将被转换成类似结构的汇编语言 [for ex IL (intermediate language) for C#, ByteCode for java]。

中间码只有在应用程序需要时才转换成机器语言,需要的代码只转换成机器码。

JIT 与非 JIT 比较:

在 JIT 中,并非所有代码都首先转换为机器码 必要的代码将被转换为机器代码 那么如果调用的方法或功能不在机器中,那么 会变成机器码……减轻CPU的负担。

由于机器代码将在运行时生成....JIT 编译器将生成针对运行进行优化的机器代码 机器的 CPU 架构。

JIT 示例:

    在 Java 中 JIT 在 JVM(Java 虚拟机)中 在 C# 中它位于 CLR(公共语言运行时)中 在 android 中,它位于 DVM(Dalvik 虚拟机)中,或者在较新版本中位于 ART(Android 运行时)中。

【讨论】:

JIT 在支持真正泛型类型的框架中提供了一些特殊优势;可以定义一个通用方法,该方法能够生成无限范围的类型,每种类型都需要不同的机器代码,但只有 JIT 为实际生成的类型生成代码。相比之下,在 C++ 中,编译器必须为程序将使用的所有类型生成代码。 JVM 在第一次运行时不会 JIT 代码。前几次,它解释字节码。然后,如果该代码运行得足够频繁,它可能会决定对它进行 JIT 处理。 您说 Java 中的 JIT 是 JVM。但是我们已经将编译后的代码提供给了 JVM,不是吗?然后它再次编译你的意思是? @KorayTugay - 我们向 JVM 提供字节码,JVM 会根据需要将其中的一部分转换为机器码。因此可以节省资源。 在 Java 中 JIT 不是 JVM。这只是其中的一部分。【参考方案4】:

正如其他人提到的那样

JIT 代表 Just-in-Time,这意味着代码在需要时被编译,而不是在运行时之前。

只是为了在上面的讨论中添加一点,JVM 维护一个函数执行多少次的计数。如果这个计数超过预定义的限制,JIT 将代码编译成可以直接由处理器执行的机器语言(与 javac 将代码编译成字节码然后 java - 解释器逐行解释这个字节码将其转换为机器码并执行)。

同样,下次计算此函数时,将再次执行相同的编译代码,这与正常解释不同,其中代码被逐行再次解释。这使执行速度更快。

【讨论】:

【参考方案5】:

JIT 编译器仅在第一次执行时将字节码编译为等效的本机代码。在每次连续执行时,JVM 仅使用已编译的本机代码来优化性能。

如果没有 JIT 编译器,JVM 解释器会逐行翻译字节码,使其看起来好像正在执行本机应用程序。

Source

【讨论】:

我对 JIT 的解释是它的作用类似于记忆,其中经常使用的函数被“存储”,并且绕过了从 java 字节码编译为本地 ISA 相关代码的费用。如果这是正确的,为什么 java 不从一开始就完全编译为本机代码?这会减少任何类型的运行时编译并使 java 对机器“原生”吗? 因为它会延迟应用程序的启动。 JIT 支持快速启动并加速应用程序执行。这是一个权衡。 我不知道字节码被解释了谢谢你的信息【参考方案6】:

JIT 代表 Just-in-Time,这意味着代码在需要时编译,而不是在运行时之前编译。

这是有益的,因为编译器可以生成针对您的特定机器优化的代码。静态编译器,就像您的普通 C 编译器一样,会将所有代码编译为开发人员机器上的可执行代码。因此,编译器将根据一些假设执行优化。它可以更慢地编译并进行更多优化,因为它不会减慢用户程序的执行速度。

【讨论】:

为什么编译后的代码不存储在用户计算机的某个地方,以便下次运行应用程序时 JIT 不必再次重新编译它们? 很好的观察结果。可以这样做,但它是否真的有益取决于应用程序的平台和使用情况。 JIT 优化不一定与离线优化或提前优化相同,因此好处可能只是“不是 JITting”,这可能有很大帮助,也可能没有多大帮助。【参考方案7】:

Java 编译器生成字节码(与架构无关)后,将由 JVM(在 Java 中)处理执行。字节码会被加载器加载到JVM中,然后每条字节指令都会被解释。

当我们需要多次调用一个方法时,我们需要多次解释相同的代码,这可能会花费比需要更多的时间。所以我们有 JIT(即时)编译器。当字节被加载到 JVM(它的运行时)时,整个代码将被编译而不是解释,从而节省时间。

JIT 编译器只在运行时工作,所以我们没有任何二进制输出。

【讨论】:

整个代码在加载到 JVM 时并没有被编译,因为关于如何进行编译的信息(阅读:指南)很少。请记住,性能是最终目标。 JIT 是相当有选择性的:监控和选择最流行的优化方法。它会一直这样做,直到各个方法达到最大优化水平。【参考方案8】:

即时编译器 (JIT): 它将 java 字节码编译成特定 CPU 的机器指令。

例如,如果我们的 java 代码中有一个循环语句:

while(i<10)
    // ...
    a=a+i;
    // ...
 

如果i的值为0,上述循环代码运行10次。

没有必要一次又一次地编译字节码 10 次,因为同一条指令将执行 10 次。在这种情况下,只需要编译该代码一次,并且可以将值更改为所需的次数。因此,即时 (JIT) 编译器会跟踪此类语句和方法(如前所述),并将此类字节码编译成机器码以获得更好的性能。

另一个类似的例子是在字符串/句子列表中使用“正则表达式”搜索模式。

JIT 编译器不会将所有代码编译为机器码。它在运行时编译具有相似模式的代码。

查看此Oracle documentation on Understand JIT 了解更多信息。

【讨论】:

“没有必要一次又一次地编译字节码 10 次,因为同一条指令将执行 10 次” - 常规编译器呢?这段代码会编译几次吗?【参考方案9】:

即时编译器 (JIT) 是一种软件,它接收不可执行的输入并返回要执行的适当机器代码。例如:

Intermediate representation    JIT    Native machine code for the current CPU architecture

     Java bytecode            --->        machine code
     javascript (run with V8) --->        machine code

这样做的结果是,对于特定的 CPU 架构,必须安装适当的 JIT 编译器。

差异编译器、解释器和 JIT

虽然我们想将源代码转换为我们可以使用的机器码时通常会有例外:

    编译器:获取源代码并返回可执行文件 解释器:逐条执行程序。它获取源代码的一个可执行段并将该段转换为机器指令。重复此过程,直到所有源代码都转换为机器指令并执行。 JIT:JIT 的许多不同实现是可能的,但是 JIT 通常是编译器和解释器的组合。 JIT 首先通过解释将它接收到的中间数据(例如 Java 字节码)转换为机器语言。 JIT 通常可以测量代码的某个部分何时经常执行,并将编译该部分以加快执行速度。

【讨论】:

【参考方案10】:

您的代码被编译成某种 IL(中间语言)。当您运行程序时,计算机不理解此代码。它只理解本机代码。因此,JIT 编译器会即时将您的 IL 编译为本机代码。它在方法级别执行此操作。

【讨论】:

“方法级别”是什么意思? 这是不正确的,它是由解释器运行的,JIT 只会在相关方法达到 CompileThreshold 后才会启动【参考方案11】:

我知道这是一个旧线程,但运行时优化是 JIT 编译的另一个重要部分,这里似乎没有讨论。基本上,JIT 编译器可以在程序运行时对其进行监控,以确定改进执行的方法。然后,它可以在运行时即时进行这些更改。 Google JIT 优化(javaworld 有个漂亮的good article about it.)

【讨论】:

【参考方案12】:

Jit 代表即时编译器 jit 是一个程序,可以将 java 字节码转换为可以直接发送到处理器的指令。

在特定系统平台使用java即时编译器(实际上是第二编译器)将字节码编译成特定的系统代码,一旦代码被jit编译器重新编译,它通常会在特定系统中运行得更快。计算机。

即时编译器随虚拟机一起提供,可供选择使用。它将字节码编译为特定于平台的可执行代码,立即执行。

【讨论】:

【参考方案13】:

即时 (JIT) 编译(也称为动态翻译或运行时编译)是一种执行计算机代码的方式,它在执行期间涉及编译程序的 - 在运行时 - 而不是在执行之前

IT 编译是结合两种传统的机器代码翻译方法 - 提前编译 (AOT)解释 strong> - 并结合了两者的一些优点和缺点。 JIT 编译结合了编译代码的速度和解释的灵活性

让我们考虑一下 JVM 中使用的 JIT,

例如,HotSpot JVM JIT 编译器会生成动态优化。换句话说,它们会在 Java 应用程序运行时做出优化决策,并生成针对底层系统架构的高性能本机机器指令

When a method is chosen for compilation, the JVM feeds its bytecode to the Just-In-Time compiler (JIT). JIT 需要理解字节码的语义和语法才能正确编译方法。为了帮助 JIT 编译器分析该方法,首先将其字节码重新格式化为称为跟踪树的内部表示,它更类似于机器码而不是字节码。然后对该方法的树进行分析和优化。最后,树被翻译成本地代码。

跟踪树是在编程代码的运行时编译中使用的数据结构。跟踪树用于一种“即时编译器”,跟踪热点期间执行的代码并对其进行编译。参考this。

参考:

http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html https://en.wikipedia.org/wiki/Just-in-time_compilation

【讨论】:

【参考方案14】:

非 JIT 编译器获取源代码并在编译时将其转换为机器特定的字节码。 JIT 编译器获取在编译时生成的与机器无关的字节码,并在运行时将其转换为特定于机器的字节码。 Java 使用的 JIT 编译器允许单个二进制文件无需修改即可在多个平台上运行。

【讨论】:

【参考方案15】:

80% 的时间使用 20% 的字节码。 JIT 编译器获取这些统计信息并通过添加内联方法、删除未使用的锁等以及创建特定于该机器的字节码来优化这 20% 的字节码以更快地运行。我引用这篇文章,我发现它很方便。 http://java.dzone.com/articles/just-time-compiler-jit-hotspot

【讨论】:

不确定为什么它被标记为 -1。我认为这里的重点是运行时统计信息用于帮助优化。 是的,但答案并没有这样说。从字面上看,JIT 不会优化最热门的 20% 的代码。【参考方案16】:

Just In Time 编译器也称为 JIT 编译器,用于 Java中的性能改进。默认情况下启用。它是 编译在执行时更早完成。 Java 通过将 JIT 编译器包含在 JVM。

【讨论】:

【参考方案17】:

JIT 是指少数 JVM 实现中的执行引擎,一种速度更快但需要更多内存的执行引擎,是一种即时编译器。在此方案中,方法的字节码在第一次调用该方法时被编译为本机机器码。然后缓存该方法的本机机器代码,以便下次调用相同的方法时可以重新使用它。

【讨论】:

如果你不提供新的/更好的东西,我会避免回答这样的问题。如果您有任何反应,则可能是投反对票或批评:您的回答不准确。 “JIT”不限于Java Virtual Machine,“更快但使用更多内存”是一种可能的效果,但不是 JIT 概念所固有的,并且方法通常不会在第一次调用时编译,而是在几次之后很明显总体而言,花时间在 JIT 上是有利的。【参考方案18】:

出于性能原因,JVM 实际上会在运行时执行编译步骤。这意味着 Java 没有干净的编译执行分离。它首先进行所谓的从 Java 源代码到字节码的静态编译。然后这个字节码被传递给 JVM 执行。但是执行字节码很慢,因此 JVM 测量字节码运行的频率,当它检测到运行非常频繁的代码“热点”时,它会执行从字节码到“热点”代码的机器码的动态编译(热点分析器)。今天,Java 程序如此有效地由机器码执行来运行。

【讨论】:

以上是关于即时 (JIT) 编译器有啥作用?的主要内容,如果未能解决你的问题,请参考以下文章

jit即时编译

jit即时编译

Zend JIT 即时编译器开源

『GCTT 出品』使用 Go 语言写一个即时编译器(JIT)

浅析 JIT 即时编译技术

Flutter在Debug和Release下分别使用啥编译模式,有啥区别?