117

Sun 的规范 JVM 实现对字节码进行了一些非常复杂的优化,以便在代码运行几次后获得接近本机的执行速度。

问题是,为什么不将此编译后的代码缓存到磁盘以供后续使用同一函数/类时使用?

就目前而言,每次执行程序时,JIT 编译器都会重新启动,而不是使用代码的预编译版本。当字节码本质上被解释时,添加这个特性不会显着增加程序的初始运行时间吗?

4

5 回答 5

31

Oracle 的 JVM确实被记录在案——引用 Oracle 的话,

编译器可以利用 Oracle JVM 的类解析模型来选择性地跨数据库调用、会话或实例持久保存已编译的 Java 方法。当已知 Java 代码在语义上没有改变时,这种持久性避免了跨会话或实例的不必要重新编译的开销。

我不知道为什么所有复杂的 VM 实现都不提供类似的选项。

于 2010-01-02T19:14:06.323 回答
31

如果不使用 @MYYN 发布的链接的剪切粘贴,我怀疑这是因为 JVM 执行的优化不是静态的,而是基于数据模式和代码模式的动态的。这些数据模式很可能会在应用程序的生命周期内发生变化,从而使缓存的优化不是最优的。

因此,您需要一种机制来确定保存的优化是否仍然是最佳的,此时您不妨立即重新优化。

于 2010-01-02T19:18:54.533 回答
19

对现有答案的更新 - Java 8 有一个专门用于解决此问题的 JEP:

=> JEP 145:缓存编译代码新链接

在非常高的层次上,它的既定目标是

保存并重用以前运行的已编译本机代码,以缩短大型 Java 应用程序的启动时间。

希望这可以帮助。

于 2013-12-31T14:55:45.967 回答
8

Excelsior JET从 2001 年发布的 2.0 版开始就有缓存 JIT 编译器。此外,它的 AOT 编译器可以使用所有优化将缓存重新编译为单个 DLL/共享对象。

于 2010-01-21T06:04:09.763 回答
1

我不知道实际原因,没有以任何方式参与 JVM 实现,但我能想到一些似是而非的原因:

  • Java 的想法是成为一种一次编写,随处运行的语言,将预编译的东西放入类文件中有点违反这一点(只有“一种”,因为当然实际的字节码仍然存在)
  • 它会增加类文件的大小,因为您将在那里多次使用相同的代码,特别是如果您碰巧在多个不同的 JVM 下运行相同的程序(这并不少见,当您认为不同的版本是不同的 JVM 时,您真的必须做)
  • 类文件本身可能不可写(尽管很容易检查)
  • JVM 优化部分基于运行时信息,并且在其他运行时它们可能不适用(尽管它们仍然应该提供一些好处)

但我真的在猜测,正如你所看到的,我真的不认为我的任何理由都是真正的阻碍。我认为 Sun 只是不将这种支持视为优先事项,也许我的第一个原因接近事实,因为习惯性地这样做也可能会导致人们认为 Java 类文件确实需要为每个 VM 提供单独的版本,而不是跨平台。

我的首选方法实际上是拥有一个单独的字节码到本机的转换器,您可以使用它事先明确地执行类似的操作,创建为特定 VM 明确构建的类文件,其中可能包含原始字节码,以便您也可以在不同的虚拟机上运行。但这可能来自我的经验:我大部分时间都在做 Java ME,Java 编译器在编译方面并不聪明,这真的很痛苦。

于 2010-01-02T19:22:14.760 回答