Sun 的规范 JVM 实现对字节码进行了一些非常复杂的优化,以便在代码运行几次后获得接近本机的执行速度。
问题是,为什么不将此编译后的代码缓存到磁盘以供后续使用同一函数/类时使用?
就目前而言,每次执行程序时,JIT 编译器都会重新启动,而不是使用代码的预编译版本。当字节码本质上被解释时,添加这个特性不会显着增加程序的初始运行时间吗?
Sun 的规范 JVM 实现对字节码进行了一些非常复杂的优化,以便在代码运行几次后获得接近本机的执行速度。
问题是,为什么不将此编译后的代码缓存到磁盘以供后续使用同一函数/类时使用?
就目前而言,每次执行程序时,JIT 编译器都会重新启动,而不是使用代码的预编译版本。当字节码本质上被解释时,添加这个特性不会显着增加程序的初始运行时间吗?
Oracle 的 JVM确实被记录在案——引用 Oracle 的话,
编译器可以利用 Oracle JVM 的类解析模型来选择性地跨数据库调用、会话或实例持久保存已编译的 Java 方法。当已知 Java 代码在语义上没有改变时,这种持久性避免了跨会话或实例的不必要重新编译的开销。
我不知道为什么所有复杂的 VM 实现都不提供类似的选项。
如果不使用 @MYYN 发布的链接的剪切粘贴,我怀疑这是因为 JVM 执行的优化不是静态的,而是基于数据模式和代码模式的动态的。这些数据模式很可能会在应用程序的生命周期内发生变化,从而使缓存的优化不是最优的。
因此,您需要一种机制来确定保存的优化是否仍然是最佳的,此时您不妨立即重新优化。
对现有答案的更新 - Java 8 有一个专门用于解决此问题的 JEP:
=> JEP 145:缓存编译代码。新链接。
在非常高的层次上,它的既定目标是:
保存并重用以前运行的已编译本机代码,以缩短大型 Java 应用程序的启动时间。
希望这可以帮助。
Excelsior JET从 2001 年发布的 2.0 版开始就有缓存 JIT 编译器。此外,它的 AOT 编译器可以使用所有优化将缓存重新编译为单个 DLL/共享对象。
我不知道实际原因,没有以任何方式参与 JVM 实现,但我能想到一些似是而非的原因:
但我真的在猜测,正如你所看到的,我真的不认为我的任何理由都是真正的阻碍。我认为 Sun 只是不将这种支持视为优先事项,也许我的第一个原因接近事实,因为习惯性地这样做也可能会导致人们认为 Java 类文件确实需要为每个 VM 提供单独的版本,而不是跨平台。
我的首选方法实际上是拥有一个单独的字节码到本机的转换器,您可以使用它事先明确地执行类似的操作,创建为特定 VM 明确构建的类文件,其中可能包含原始字节码,以便您也可以在不同的虚拟机上运行。但这可能来自我的经验:我大部分时间都在做 Java ME,Java 编译器在编译方面并不聪明,这真的很痛苦。