I have a Java Maven project with about 800 source files (some generated by javacc/JTB) which is taking a good 25 minutes to compile with javac.
When I changed my pom.xml over to use the Eclipse compiler, it takes about 30 seconds to compile.
Any suggestions as to why javac (1.5) is running so slowly? (I don’t want to switch over to the Eclipse compiler permanently, as the plugin for Maven seems more than a little buggy.)
I have a test case which easily reproduces the problem. The following code generates a number of source files in the default package. If you try to compile ImplementingClass.java with javac, it will seem to pause for an inordinately long time.
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(); } }
You get the same behaviour with JDK 1.6, including update 14, build 04, using G1 doesn’t change the behaviour, (though G1 appears to work really well).
Monitoring javac with jvisualvm, repeated thread dumps show the main thread spending lots of time in
and churning through a large number of short lived instances of these classes:
I suspect the code is churning through
com.sun.tools.javac.comp.Check.checkCompatibleConcretescomparing each method with every other methodThat method’s javadoc:
It may be that eclipse’s compiler either doesn’t perform that check, or doesn’t perform it in the same way.