我有一个Java Maven项目,其中包含大约800个源文件(有些是由javacc / JTB生成的),用Javac编译需要25分钟。
当我将pom.xml更改为使用Eclipse编译器时,编译大约需要30秒。
关于javac(1.5)为什么运行如此缓慢的任何建议?(我不想永久切换到Eclipse编译器,因为Maven的插件似乎不止是个小问题。)
我有一个容易重现问题的测试用例。以下代码在默认程序包中生成许多源文件。如果尝试使用javac编译ImplementingClass.java,它似乎会暂停很长时间。
import java.io.File; import java.io.FileNotFoundException; import java.io.PrintStream; public class CodeGenerator { private final static String PATH = System.getProperty("java.io.tmpdir"); private final static int NUM_TYPES = 1000; public static void main(String[] args) throws FileNotFoundException { PrintStream interfacePs = new PrintStream(PATH + File.separator + "Interface.java"); PrintStream abstractClassPs = new PrintStream(PATH + File.separator + "AbstractClass.java"); PrintStream implementingClassPs = new PrintStream(PATH + File.separator + "ImplementingClass.java"); interfacePs.println("public interface Interface<T> {"); abstractClassPs.println("public abstract class AbstractClass<T> implements Interface<T> {"); implementingClassPs.println("public class ImplementingClass extends AbstractClass<Object> {"); for (int i=0; i<NUM_TYPES; i++) { String nodeName = "Node" + i; PrintStream nodePs = new PrintStream(PATH + File.separator + nodeName + ".java"); nodePs.printf("public class %s { }\n", nodeName); nodePs.close(); interfacePs.printf("void visit(%s node, T obj);%n", nodeName); abstractClassPs.printf("public void visit(%s node, T obj) { System.out.println(obj.toString()); }%n", nodeName); } interfacePs.println("}"); abstractClassPs.println("}"); implementingClassPs.println("}"); interfacePs.close(); abstractClassPs.close(); implementingClassPs.close(); } }
您使用JDK 1.6会得到相同的行为,包括更新14,内部版本04,使用G1不会改变其行为(尽管G1看起来确实工作得很好)。
使用jvisualvm监视javac,重复的线程转储显示了主线程花费大量时间在
at com.sun.tools.javac.code.Types.isSubSignature(Types.java:1846) at com.sun.tools.javac.code.Symbol$MethodSymbol.overrides(Symbol.java:1108) at com.sun.tools.javac.code.Symbol$MethodSymbol.implementation(Symbol.java:1159) at com.sun.tools.javac.comp.Check.checkCompatibleConcretes(Check.java:1239) at com.sun.tools.javac.comp.Check.checkCompatibleSupertypes(Check.java:1567) at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:2674) at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:2628) at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:2564) at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1036) at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:765) at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:730) at com.sun.tools.javac.main.Main.compile(Main.java:353) at com.sun.tools.javac.main.Main.compile(Main.java:279) at com.sun.tools.javac.main.Main.compile(Main.java:270) at com.sun.tools.javac.Main.compile(Main.java:69) at com.sun.tools.javac.Main.main(Main.java:54)
并通过大量这些类的短暂实例进行搅动:
com.sun.tools.javac.code.Types$Subst com.sun.tools.javac.util.List com.sun.tools.javac.code.Types$MethodType
我怀疑通过com.sun.tools.javac.comp.Check.checkCompatibleConcretes将每种方法与其他方法进行比较 会搅乱代码
com.sun.tools.javac.comp.Check.checkCompatibleConcretes
该方法的javadoc:
/** Check that a class does not inherit two concrete methods * with the same signature. */
可能是eclipse的编译器未执行该检查,或者未以相同的方式执行该检查。