2

从我读过的java(通常)似乎将java编译为不是很优化的java字节码(根本不是?),把它留给jit来优化。这是真的?如果是的话,是否有任何探索(可能在替代实现中)让编译器优化代码以减少 jit 的工作量(这可能吗)?

还有很多人似乎不喜欢 Java(和许多其他高级内存管理语言)的本机代码生成(有时称为提前编译),原因有很多,例如失去可移植性(等等),但是也部分是因为(至少对于那些具有即时编译器的语言)的想法是,提前编译为机器代码会错过 jit 编译器可以完成的可能优化,因此从长远来看可能会更慢.

这让我想知道是否有人尝试过实现http://en.wikipedia.org/wiki/Profile-guided_optimization(编译成二进制文件+一些额外的然后运行程序并分析测试运行的运行时信息以生成java /(其他内存管理语言)的希望为现实世界使用更优化的二进制文件,以及与 jit 代码相比如何?有人有线索吗?

4

3 回答 3

4

个人认为,最大的区别不是JIT编译和AOT编译,而是类编译和全程序优化。

当您运行 javac 时,它只查看单个 .java 文件,并将其编译为单个 .class 文件。所有接口实现和虚拟方法和覆盖都经过有效性检查,但未解决(因为不分析整个程序就不可能知道真正的方法调用目标)。

JVM 使用“运行时加载和链接”将所有类组装成一个连贯的程序(程序中的任何类都可以调用专门的行为来更改默认的加载/链接行为)。

但是,在运行时,JVM 可以删除绝大多数虚拟方法。它可以内联所有的 getter 和 setter,将它们变成原始字段。当这些原始字段被内联时,它可以执行常量传播以进一步优化代码。(在运行时,没有私有字段之类的东西。)如果只有一个线程在运行,JVM 可以消除所有同步原语。

长话短说,有很多优化在不分析整个程序的情况下是不可能的,而进行整个程序分析的最佳时间是在运行时。

于 2010-07-12T22:27:45.717 回答
2

Profile-guided optimization 有一些注意事项,其中之一甚至在您链接的 Wiki 文章中也提到过。它的结果是有效的

  • 对于给定的示例,表示用户或其他代码实际使用您的代码的方式。
  • 对于给定的平台(CPU、内存+其他硬件、操作系统等)。
    从性能的角度来看,即使在通常被认为(或多或少)相同的平台之间也存在相当大的差异(例如,比较单核,旧的 Athlon 与 512M 与 6 核 Intel 与 8G,在 Linux 上运行,但与非常不同的内核版本)。
  • 对于给定的 JVM 及其配置。

如果其中任何一个发生变化,那么您的分析结果(以及基于它们的优化)不再需要有效。很可能一些优化仍然会产生有益的影响,但其中一些可能会变得不理想(甚至会降低性能)。

正如前面提到的,JIT JVM 做的事情与分析非常相似,但它们是在运行中进行的。它也被称为“热点”,因为它不断地监控执行的代码,寻找频繁执行的热点,并尝试只优化那些部分。在这一点上,它将能够利用有关代码的更多知识(了解它的上下文,其他类如何使用它等)所以 - 正如您和其他答案所提到的 - 它可以做更好的优化作为静态的。它将继续监控,如果需要,它将在稍后进行另一轮优化,这一次会更加努力(寻找更多、更昂贵的优化)。
处理现实生活中的数据(使用统计 + 平台 + 配置)可以避免前面提到的警告。

它的代价是它需要花费在“分析”+ JIT 上的一些额外时间。大多数时候它度过的很好。

我想配置文件引导的优化器仍然可以与之竞争(甚至击败它),但只有在某些特殊情况下,如果你可以避免警告:

  • 您非常确定您的样本很好地代表了现实生活场景,并且它们在执行过程中不会发生太大变化。
  • 您非常准确地了解您的目标平台,并且可以对其进行分析。
  • 当然,您知道/控制 JVM 及其配置。

它很少发生,我猜一般来说 JIT 会给你更好的结果,但我没有证据证明它。

如果您的目标是无法进行 JIT 优化的 JVM(我认为大多数小型设备都有这样的 JVM),那么从配置文件引导的优化中获得价值的另一种可能性。

BTW one disadvantage mentioned in other answers would be quite easy to avoid: if static/profile guided optimization is slow (which is probably the case) then do it only for releases (or RCs going to testers) or during nightly builds (where time does not matter so much).
I think the much bigger problem would be to have good sample test cases. Creating and maintaining them is usually not easy and takes a lot of time. Especially if you want to be able to execute them automatically, which would be quite essential in this case.

于 2010-07-21T07:53:59.063 回答
1

官方的 Java Hot Spot 编译器在运行时进行“自适应优化”,这与您提到的配置文件引导优化基本相同。长期以来,这至少是这个特定 Java 实现的一个特性。

在编译时预先执行更多静态分析或优化传递的权衡本质上是您从这些额外工作中获得的(不断减少的)回报与编译器运行所需的时间相比。像 MLton(用于标准 ML)这样的编译器是具有大量静态检查的全程序优化编译器。它可以生成非常好的代码,但在大中型程序上变得非常非常慢,即使在快速系统上也是如此。

因此,Java 方法似乎是尽可能地使用 JIT 和自适应优化,初始编译过程只生成可接受的有效二进制文件。绝对相反的一端是使用类似于 MLKit 之类的方法,它对区域和内存行为进行大量静态推断。

于 2010-07-20T22:06:51.513 回答