编译器是否存在差异 - java

时间:2013-10-02 08:00:08

标签: java optimization compiler-construction bytecode

相同版本的代码优化是否有任何差异: Oracle Java编译器 Apache Java编译器 IBM Java编译器 OpenJDK Java编译器。 如果有什么代码可以演示不同的优化?或者他们使用相同的编译器?如果没有已知的优化差异,那么我在哪里可以找到有关如何针对不同优化测试编译器的资源?

3 个答案:

答案 0 :(得分:3)

不,他们不使用相同的编译器。我不能对优化和内容做出太多评论,但这里有一个例子,编译器的工作方式有所不同。

public class Test {
    public static void main(String[] args) {
        int x = 1L;  // <- this cannot compile
    }
}

如果使用标准的java编译器,它将抛出编译错误,并且不会创建类文件。

但是如果你对java ECJ使用eclipse编译器,它不仅会抛出相同的编译错误,而且还会创建一个类文件( YES ,一个类文件一个无法编译的代码,这使得ECJ,我不会说错,但有点棘手),看起来像这样。

public static void main(String[] paramArrayOfString)
{
    throw new Error("Unresolved compilation problem: \n\tType mismatch: cannot convert from long to int.\n");
}

话虽如此,这只是在两个编译器之间。其他编译器可能有自己的工作方式。

P.S:我从here获取此示例。

答案 1 :(得分:3)

  

相同版本的代码优化是否存在差异:Oracle Java编译器Apache Java编译器IBM Java编译器OpenJDK Java编译器。

虽然编译器可能非常不同,但javac几乎没有优化。主要优化是常量内联,这在JLS中指定,因此是标准的(除了任何错误)

  

如果有什么代码可以演示不同的优化?

你可以这样做。

final String w = "world";
String a = "hello " + w;
String b = "hello world";
String c = w;
String d = "hello " + c;
System.out.prinlnt(a == b); // these are the same String
System.out.prinlnt(c == b); // these are NOT the same String

在第一种情况下,常量被内联并且String在编译时连接在一起。在第二种情况下,连接在运行时执行,并创建了一个新的String。

  

或者他们使用相同的编译器?

不,但99%的优化是在运行时由JIT执行的,因此对于给定版本的JVM,它们是相同的。

  

如果没有已知的优化差异,那么我在哪里可以找到有关如何针对不同优化测试编译器的资源?

如果有一个,我会感到惊讶,因为这听起来不是很有用。问题是JIT优化了预先构建的字节代码模板,如果你试图优化字节代码,最终可能会混淆JIT并使代码变慢。即,如果不考虑将运行的JVM,就无法评估优化。

答案 2 :(得分:0)

我花费大量时间的唯一编译器是javac(正如其他人所指出的那样,在热切的优化方面做得很少)和Eclipse编译器。

在编写Java反编译器时,我观察到Eclipse编译代码的方式有些(通常令人沮丧),但并不多。其中一些可以被认为是优化。其中:

  1. Eclipse编译器似乎至少执行一些重复的代码分析。如果两个(或更多?)代码块都分支到单独但等效的代码块,则可以将等效目标块展平为具有多个条目跳转的单个块。我从未见过javac执行此类优化;总是会发出等效的块。我记得的所有例子都发生在switch陈述中。此优化减少了方法大小(因此减小了类文件大小),这可以改善负载和验证时间。它甚至可以在解释模式下提高性能(特别是如果有问题的解释器执行内联),但我想这样的改进会很轻微。我怀疑一旦方法被JIT编译就会有所作为。它还使反编译更加困难(grrr)。

  2. 基本块通常以与javac完全不同的顺序发出。这可能只是编译器内部设计的副作用,或者可能是编译器正在尝试优化代码布局以减少跳转次数。这是我通常会给JIT留下的一种优化,而且这种哲学似乎适用于javac