ChatGPT解决这个技术问题 Extra ChatGPT

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

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


M
Mark Cidade

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

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

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


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

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

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

Just-In-Time (JIT) 编译器是运行时解释器的一个特性,它不是每次调用方法时都解释字节码,而是将字节码编译成运行机器的机器代码指令,然后调用它而是目标代码。理想情况下,运行目标代码的效率将克服每次运行时重新编译程序的低效率。


然而,这句话“即时 (JIT) 编译器是运行时解释器的一个特性” 会引起混淆;例如 - stackoverflow.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 无关,而且它也不是一个完整的解决方案。它现在肯定不可行。)
B
Brian Tompsett - 汤莱恩

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。它只是其中的一部分。
A
Aniket Thakur

正如其他人提到的

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

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

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


佚名

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

https://i.stack.imgur.com/hSTYc.png

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

https://i.stack.imgur.com/5sZie.png

Source


我对 JIT 的解释是,它的作用类似于记忆,其中经常使用的函数被“存储”,并且绕过了从 java 字节码编译为本地 ISA 相关代码的费用。如果这是正确的,为什么 java 不从一开始就完全编译为本机代码?这会减少任何类型的运行时编译并使 java 对机器“原生”吗?
因为它会延迟应用程序的启动。 JIT 支持快速启动并加速应用程序执行。这是一个权衡。
我不知道字节码被解释了谢谢你的信息
我还检查了源代码,但我认为这不是典型的 JVM 实现。这取决于实现,但这不是我认为的通常的现代 JVM。有人可以澄清这个答案是正确的还是现代JVM不同?
B
Brian Lyttle

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

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


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

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

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

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


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

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

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

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

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

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

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

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

请参阅此Oracle documentation on Understand JIT以了解更多信息。


“没有必要一次又一次地编译字节码 10 次,因为同一条指令将执行 10 次” - 常规编译器怎么样?它会编译这件作品几次吗?
W
Willem van der Veen

即时编译器 (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 通常可以测量代码的某个部分何时经常执行,并将编译该部分以更快地执行。


C
Charles Graham

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


你是什么意思“方法级别”?
这是不正确的,它是由解释器运行的,JIT 只会在相关方法达到 CompileThreshold 后才会启动
e
eze

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


u
user3459027

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

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

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


p
prime

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

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

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

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

选择用于编译的方法时,JVM将其字节码馈送到恰好的编译器(JIT)。 JIT 需要理解字节码的语义和语法才能正确编译方法。为了帮助 JIT 编译器分析该方法,首先将其字节码重新表述为称为跟踪树的内部表示,它更类似于机器码而不是字节码。然后对该方法的树进行分析和优化。最后,树被翻译成本地代码。

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

参考 :

http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

https://en.wikipedia.org/wiki/Just-in-time_compilation


佚名

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


S
Santosh budhe

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


不知道为什么这被标记为-1。我认为这里的重点是运行时统计信息用于帮助优化。
是的,但答案并没有那样说。从字面上看,JIT 不会优化最热门的 20% 的代码。
G
Ganesh Giri

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


V
Venkata Santhosh Piduri

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


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

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