3

可能重复:
为什么 JVM 不缓存 JIT 编译代码?

我知道 JIT 编译是使用热点机制编译为本机代码,它可以非常非常快,因为它是对 OS、Hardwards 等的优化。

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

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

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

4

5 回答 5

3

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

使用 Java,不能保证代码是 JVM 的本地代码。小程序就是一个很好的例子,Webstart 也说明了这一点。通用的“保持优化”只会在很少运行的代码中弄乱缓存,并在何处保留优化的扩展时产生问题。

在知道磁盘缓存保留多长时间方面也会产生相当大的难题,并且您是否不必重新编译“类”文件以验证缓存是否用于类文件的正确“释放”?Java 没有相同类文件指示符的“此版本”,但可选的串行版本 uid 除外。

通过检查类文件的总和并将其放置在已编译类的字段中,也许有一种解决方法,但我不想考虑 JVM 的启动时间,该 JVM 的任务是扫描所有缓存的机器特定代码、构建表、干预类加载器,并使用优化代码检查加载类的校验和。

于 2012-07-25T15:02:37.417 回答
2

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

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

于 2012-07-25T14:56:55.357 回答
2

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

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

  • Java 没有像 .net 那样用于其程序集的良好 ID 机制。但是确实可以使用散列(在 jar 或类级别)。
  • 它主要(仅?)在应用程序启动时受益。从 JRE6 开始,启动速度变得更快。
于 2012-07-25T16:55:17.487 回答
2

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

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

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

于 2012-07-25T15:29:00.877 回答
2

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

另一个问题是 JIT 代码通常包含地址空间特定值(例如:给定静态变量的地址,或另一个 JIT 方法的入口点),并且这些值可以(而且肯定会!)在每次 JVM 调用时发生变化,所以同样,在处理这些问题时必须小心。

AOT 代码提供的性能优势是真实的,该功能非常值得根据情况使用。(特别是:事情不会改变运行,等等 - 比如调用相同版本的应用服务器或 Eclipse,例如)

于 2012-07-26T03:15:46.647 回答