【问题标题】:Does a JIT compiler have any disadvantages compared to a traditional compiler? [duplicate]与传统编译器相比,JIT 编译器有什么缺点吗? [复制]
【发布时间】:2010-07-11 04:29:02
【问题描述】:

可能重复:
JIT compiler vs offline compilers

所以直到几分钟前,我才真正理解 JIT 编译器和解释器之间的区别。浏览SO,我找到了答案,这在标题中提出了问题。据我所知,JIT 编译器的好处是能够使用运行它的特定处理器,从而可以制作更好的优化程序。谁能给我比较一下各自的优缺点?

【问题讨论】:

  • 我认为这根本不是另一个问题的重复,因为另一个问题与这个问题完全相反:“是否存在 JIT 编译器比其他编译器更快的情况,例如C++?” (如果关闭,我将投票重新开放。)

标签: compiler-construction jit


【解决方案1】:

解释器、JIT 编译器和“离线”编译器

JIT 编译器和 口译员

为简单起见,我们假设解释器将运行字节码(中间代码/语言)。当 VM/解释器决定这样做更好时,JIT 编译机制会将相同的字节码翻译成针对相关硬件的本机代码,重点关注所请求的优化类型。

所以基本上一个 JIT 可能会产生一个 更快的可执行但需要更长的时间 编译?

我认为您缺少的是 JIT 编译发生在 runtime 而不是编译时(与“离线”编译器不同)

JIT 编译开销

编译代码不是免费的,也需要时间。如果它花时间编译它然后只运行它几次,它可能不会进行良好的交易。因此,VM 仍然需要决定将什么定义为“热点”并对其进行 JIT 编译。

请允许我以 Java 虚拟机 (JVM) 为例:

JVM 可以使用开关,您可以使用这些开关定义代码将被 JIT 编译的阈值。 -XX:CompileThreshold=10000

为了说明 JIT 编译时间的成本,假设您将该阈值设置为 20,并且有一段代码需要运行 21 次。在它运行 20 次之后会发生什么,VM 现在将花费一些时间来 JIT 编译它。现在你有了来自 JIT 编译的原生代码,但它只会再运行一次(21 次),这可能不会带来任何性能提升来弥补 JIT 进程。

我希望这能说明这一点。

这是一个 JVM 开关,显示 JIT 编译所花费的时间-XX:-CITime“打印在 JIT 编译器中花费的时间”

旁注:我认为这不是什么“大事”,我只是想在你提出这个问题后指出。

【讨论】:

  • 所以基本上一个 JIT 可能会产生一个更快的可执行文件但需要更长的时间来编译?
  • 我不会说它更长,但是程序运行时会有开销。
  • 哦,我想我误解了 JIT 编译器是什么。我假设它在第一次运行时会完全编译程序。它也像解释器一样工作吗?
  • @Maulrus:这取决于 JIT 编译器的目标,以及设计师想要支持的优化类型。一些 JIT 在启动时会进行完全重新编译,而另一些则在确定最需要优化的部分时编译部分。
  • 好吧,我想我现在已经明白了。谢谢!
【解决方案2】:

JIT 编译本质上并不意味着它易于反汇编。这更依赖于实现,例如 Java 二进制文件。但是请注意,JIT 可以应用于任何类型的可执行文件,无论是 Java、Python 还是已经从 C++ 或类似工具编译的二进制文件。 (IIRC,Dynamo 项目涉及即时重新编译此类二进制文件以提高性能。)

JIT 编译的权衡是,虽然进程的目标是提高运行时性能,但进程实际上也发生在运行时,因此在分析、编译和验证代码片段时会产生开销。如果实现效率低下或没有进行足够的优化,那么它实际上会导致性能下降。

另一个权衡是在某些情况下,JIT 编译可能非常浪费。例如,考虑一个自修改的可执行文件。如果您编译了一段代码,然后可执行文件修改了该片段,则您必须丢弃已编译的片段,然后重新分析该片段以确定是否值得重新编译。如果这种情况频繁发生,则会严重影响性能。

最后,内存消耗会受到影响,因为编译后的代码片段必须驻留在内存中才能生效。这对于内存有限的设备来说是不切实际的,或者很难很好地实现。

【讨论】:

  • Apple 的 Rosetta JIT 将 PowerPC 代码编译为 x86。
  • Apple 的 Mac 68K 模拟器(在 PCI PowerMac 上)也使用 JIT 编译。
  • 这两个例子都是一种特殊形式的 JIT 编译,称为二进制翻译。 (见en.wikipedia.org/wiki/Binary_translation)。我对两者都不是特别熟悉(“我是 PC”),但我想两者都使用动态二进制翻译。
【解决方案3】:

至少对我来说,缺少内联 ASM 是一个大问题。偶尔,您只想完全控制程序的一小部分的 CPU 的每个细节。即使我手头的任务不需要它,我也喜欢我的电脑能做的所有事情,原则上都可以用我的语言完成。

【讨论】:

    【解决方案4】:

    JIT 编译器有更多的内存开销,因为除了 AOT(提前)编译程序所需的运行时库和编译代码之外,它们还需要加载编译器和解释器。

    【讨论】:

      【解决方案5】:

      JIT 编译器更难编写(不是全部,但值得一提)。

      【讨论】:

        【解决方案6】:

        我想说的是使用 JIT 编译器的一个真正的缺点(实际上更多的是副作用),那就是它很容易将 IL 反汇编成人类可读的代码。

        【讨论】:

        • 不是这样的! Java 语言和 Java 字节码展示了这一特性,但编译为 Java 字节码的 JRuby 程序无法被理解地反编译。使用 Apple 的 Rosetta 将 PowerPC 程序 JIT 转换为 x86 机器代码也是如此。
        • 这也不是唯一的缺点。
        • Scala 程序在编译成 Java 字节码之前要经过几个层次的句法脱糖(这使得它们更难阅读,但并非不可能)。
        • @Ken Bloom:当然,有 .NET 的混淆程序,但不是普通的。
        • JIT 不一定适用于 IL。 HP Labs 的 Dynamo 项目基本上是 HP/UX 机器代码的 JIT。 JIT 和底层架构是完全独立的。
        猜你喜欢
        • 2011-05-01
        • 2010-10-06
        • 2011-02-23
        • 1970-01-01
        • 2020-06-20
        • 2010-10-16
        • 2019-03-01
        • 2023-03-11
        • 1970-01-01
        相关资源
        最近更新 更多