实时编译-存储与始终执行



可能重复:
为什么不';JVM是否缓存JIT编译的代码?

我知道JIT编译是使用热点机制编译到本机代码,这可能非常非常快,因为它是对操作系统、硬件等的优化。

我的问题是,为什么Java不将JIT编译的代码存储在文件中的某个位置,并将其用于将来的目的?这也可以减少"初始预热"时间。

请让我知道我在这里缺了什么。

补充我的问题:为什么Java不将完整的代码编译为本机代码,并始终使用它(用于特定的JVM、操作系统、平台)?为什么选择JIT?

虽然可以保证您将始终使用JVM,但不能保证您始终使用相同的JVM。热点优化代码仅对您的计算机有效。

对于Java,不能保证代码是JVM的本地代码。小程序就是一个完美的例子,Webstart也说明了这一点。通用的"保持优化"只会使很少运行的代码中的缓存混乱不堪,并在哪里保存优化的扩展方面产生问题。

这也会造成一个很大的难题,即知道磁盘上的缓存要保存多久,难道你不需要重新编译"类"文件来验证缓存是否适合类文件的正确"发布"吗?除了可选的串行版本uid之外,Java没有相同类文件指示符的"this version"。

也许有一种解决方法,可以对类文件进行校验和,并将其放在编译类的字段中,但我不愿意考虑JVM的启动时间,JVM的任务是扫描所有缓存的机器特定代码,构建一个表,干预类加载器,并用优化的代码检查加载类的校验和。

如果我没记错的话,已经尝试过缓存和共享JIT编译的代码,但发现这不是一个好主意。

一方面,现代HotSpot JIT编译器在当前CPU模型和当前执行的使用模式的上下文中生成并优化代码。如果要缓存已编译的代码,那么代码很有可能不是最佳的。

另一方面,显然存在各种棘手的技术问题。例如,缓存的代码成为一个潜在的安全漏洞。例如,代码区域需要由共享它的所有应用程序/用户都可以写入。但这意味着一个用户可能会干扰另一个用户的应用程序的运行。

我自己也问过这个问题。我得到的印象是,很难做到正确,避免有一个包含过时代码的商店。

解决这个问题的一种方法是做一个-XX:+PrintCompilation,并编写一个简短的预热例程来预热这些方法。

它存在于.Net中(在很多方面与java相似),它被称为NGEN。所以我不明白为什么它不能存在于java中。

我可以看出没有完成的两个原因:

  • Java没有像.net那样的好的ID机制来进行汇编。但是散列确实可以使用(在jar或类级别)
  • 在应用程序启动时,它将主要(仅?)受益。自从JRE6之后,启动速度也快了很多

一些JVM(如IBM JVM)确实具有"超前共享JIT代码"。这很难做到(正如其他答案所指出的那样),因为一个JVM一次使用的类文件可能与下次使用的文件不同,即使它们具有相同的名称。因此,需要大量的逻辑来证明"我之前看到的a类和我现在拥有的a类确实是一样的"。

另一个问题是,JITed代码经常包含特定于地址空间的值(例如:给定静态变量的地址,或另一个JITed方法的入口点),这些值在每次JVM调用时都可能(当然也会!)发生变化,因此在处理这些问题时必须小心。

AOT代码提供的性能胜利是真实的,并且该功能非常值得根据具体情况使用。(特别是:事情不会从运行变为运行,等等。比如调用同一版本的应用程序服务器,或者Eclipse)

最新更新