Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么';JVM缓存JIT编译的代码?_Java_Caching_Jvm_Compilation_Jit - Fatal编程技术网

Java 为什么';JVM缓存JIT编译的代码?

Java 为什么';JVM缓存JIT编译的代码?,java,caching,jvm,compilation,jit,Java,Caching,Jvm,Compilation,Jit,Sun的规范JVM实现对字节码进行了一些非常复杂的优化,以在代码运行几次后获得接近本机的执行速度 问题是,为什么编译后的代码没有缓存到磁盘上,以便在后续使用相同的函数/类时使用 目前,每次执行程序时,JIT编译器都会重新启动,而不是使用预编译版本的代码。当字节码基本上被解释时,添加此功能不会显著提高程序的初始运行时间吗?确实有这样的记录——引用Oracle 编译器可以利用 Oracle JVM的类解析模型 可选地持久化编译Java 跨数据库调用的方法, 会话或实例。这样的 持久性避免了 跨应用程

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

问题是,为什么编译后的代码没有缓存到磁盘上,以便在后续使用相同的函数/类时使用

目前,每次执行程序时,JIT编译器都会重新启动,而不是使用预编译版本的代码。当字节码基本上被解释时,添加此功能不会显著提高程序的初始运行时间吗?

确实有这样的记录——引用Oracle

编译器可以利用 Oracle JVM的类解析模型 可选地持久化编译Java 跨数据库调用的方法, 会话或实例。这样的 持久性避免了 跨应用程序进行不必要的重新编译 会话或实例,如果它是 从语义上讲,Java代码 没有改变


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

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


因此,您需要一种机制来确定保存的优化是否仍然是最优的,在这一点上,您还可以动态地重新优化。

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

  • Java的思想是成为一种只写一次就可以在任何地方运行的语言,而将预编译的内容放入类文件有点违反了这一点(只有“某种程度”,因为实际的字节码仍然存在)
  • <> LI>会增加类文件大小,因为在那里你会多次使用相同的代码,特别是如果你碰巧在多个不同的JVM下运行同一个程序(当你认为不同的版本是不同的JVM,你必须做的)时,这并不罕见。
  • 类文件本身可能是不可写的(尽管这很容易检查)
  • JVM优化部分基于运行时信息,而在其他运行中,它们可能并不适用(尽管它们仍应提供一些好处)
但我真的在猜测,正如你们所看到的,我真的不认为我的任何理由是真正的节目停顿。我想Sun只是不认为这个支持是一个优先事项,也许我的第一个原因是接近事实,因为这样做习惯性地也可能导致人们认为java类文件确实需要一个单独版本的每个VM而不是跨平台。
我更喜欢的方法实际上是有一个单独的字节码到本机转换器,您可以使用它来预先显式地执行类似的操作,创建为特定VM显式构建的类文件,其中可能包含原始字节码,以便您也可以使用不同的VM运行。但这可能来自我的经验:我大部分时间都在使用Java ME,Java编译器在编译方面不够聪明,这让我感到非常痛苦。

自2001年发布的2.0版以来,就有一个缓存JIT编译器。此外,其AOT编译器可以使用所有优化将缓存重新编译到单个DLL/共享对象中。

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

=>

在非常高的级别上,其声明的目标是

保存并重用以前运行中编译的本机代码,以便 提高大型Java应用程序的启动时间


希望这有帮助

一个讨论这个问题的帖子:但这是一个不太可能吸引到明确答案的问题。我不确定是否会有“显著”的提升,因为这样您就必须从磁盘加载JITted内容,而不是将其存储在内存中。它可以加快速度,但要根据具体情况而定。谢谢大家的精彩回答!所有的答案都是同样有效的,所以我在这一点上与社区一起…@Nfff3看一看,因为其他复杂的JVM没有一个响着喇叭的大型企业RDBMS来方便地存储内容:)哇!这意味着编译有时会被缓存。这是个好消息!IBM的J9也有这样做的文档记录。请注意,这个Oracle JVM是Oracle数据库中的JVM,而不是Oracle在购买Sun时获得的下载。类文件中有这样一个点,事实上这是最初的意图(将JIT’ed代码作为属性存储在类文件中)。@ToBubeer:谢谢确认。我怀疑可能是这样的(我也会这么做),但不确定。我想你的最后一颗子弹击中了我的头。其他部分可以解决,但最后一部分,我认为,是JITed代码没有持久化的主要原因。关于显式字节码到本机编译器的最后一段是您目前在.NET中使用NGEN()的部分……或者您可以将持久化作为一个选项,就像Oracle的JVM一样,授权高级程序员在他们知道模式没有改变的情况下,在他们的责任范围内优化他们应用程序的性能。为什么不呢?因为这可能不值得。如果SUN、IBM和BEA都不认为JVM的性能值得这么做,那么这将是一个很好的理由。也许他们的RT优化比Oracle快,这就是Oracle缓存RT的原因。为什么不将存储的优化作为起点,使用以前运行中学到的东西?从那时起,JIT可以像往常一样进行再操作