相同版本的代码优化是否有任何差异: Oracle Java编译器 Apache Java编译器 IBM Java编译器 OpenJDK Java编译器。 如果有什么代码可以演示不同的优化?或者他们使用相同的编译器?如果没有已知的优化差异,那么我在哪里可以找到有关如何针对不同优化测试编译器的资源?
答案 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编译代码的方式有些(通常令人沮丧),但并不多。其中一些可以被认为是优化。其中:
Eclipse编译器似乎至少执行一些重复的代码分析。如果两个(或更多?)代码块都分支到单独但等效的代码块,则可以将等效目标块展平为具有多个条目跳转的单个块。我从未见过javac
执行此类优化;总是会发出等效的块。我记得的所有例子都发生在switch
陈述中。此优化减少了方法大小(因此减小了类文件大小),这可以改善负载和验证时间。它甚至可以在解释模式下提高性能(特别是如果有问题的解释器执行内联),但我想这样的改进会很轻微。我怀疑一旦方法被JIT编译就会有所作为。它还使反编译更加困难(grrr)。
基本块通常以与javac
完全不同的顺序发出。这可能只是编译器内部设计的副作用,或者可能是编译器正在尝试优化代码布局以减少跳转次数。这是我通常会给JIT留下的一种优化,而且这种哲学似乎适用于javac
。