【问题标题】:Questions about possible java(or other memory managed language) optimizations关于可能的 java(或其他内存管理语言)优化的问题
【发布时间】:2010-07-21 16:01:58
【问题描述】:

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

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

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

【问题讨论】:

    标签: compilation jit aot


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 同意。请注意,某些 AOT 编译器(gcc 是我所知道的唯一一个,但可能还有其他编译器)确实具有此功能,并将其称为“链接时优化”。不过,它相对较新,并且仍然与猜测哪个函数最常被调用有关。尽管 OP 提到了“配置文件引导优化”。
    【解决方案2】:

    配置文件引导优化有一些注意事项,其中之一甚至在您链接的 Wiki 文章中也提到过。结果有效

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

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

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

    它的代价是它需要在“分析”+ JIT-ing 上花费一些额外的时间。大部分时间都花得很好。

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

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

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

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

    顺便说一句,其他答案中提到的一个缺点很容易避免:如果静态/配置文件引导的优化很慢(可能是这种情况),那么仅针对发布(或 RC 去测试人员)或在夜间构建期间执行此操作(时间无关紧要)。
    我认为更大的问题是要有好的样本测试用例。创建和维护它们通常并不容易,而且需要很多时间。特别是如果您希望能够自动执行它们,这在这种情况下非常重要。

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-26
        • 2011-06-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多