22

What should I do to investigate and troubleshoot a slow compilation problem?

My project has about 100 classes and takes more than 45 seconds to compile, which seems very slow to me. As a reference, I have another project with 50 classes that compiles in 3 seconds.

ps:

  • I use maven as a build tool. It takes maven ~50 seconds to compile (mvn clean compile), of which 45 seconds are spent running javac (confirmed by running with the -X option).
  • increasing the amount of memory did not help (-Xms500m)
  • I can give more info about my project but it is fairly standard so I'm not sure what information is relevant.

UPDATE

Thanks to Tagir's idea I've managed to find one of the culprits. This class adds 20 seconds to the compilation time:

import org.jooq.DSLContext;
import org.jooq.Field;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.round;
import static org.jooq.impl.DSL.sum;


class Test {
  static Object fast(DSLContext sql) {
    Field<Double> a = field("a").cast(Double.class);
    return sql.select()
            .having(round(sum(a).cast(Double.class), 2).ne(0d));
  }
  static Object slow(DSLContext sql) {
    return sql.select()
            .having(round(sum(field("a").cast(Double.class)).cast(Double.class), 2).ne(0d));
  }
}

If the slow method is commented out, the compilation time is back to normal.

Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783
  • Have you tried building with the `-X` flag, that will give you a dependency report – Kenneth Clark Jun 08 '15 at 11:03
  • 1
    Are there any autogenerated classes in your project? Have you tried to recompile it partially (e. g. delete manually class files belonging to half of the packages, recompile and measure the time) to narrow the problem down? There's a chance that one or several classes slow down the whole thing. – Tagir Valeev Jun 08 '15 at 11:04
  • @KennethClark using -X shows the parameters passed to javac then hangs for 45 seconds and then prints "build success"... – assylias Jun 08 '15 at 11:06
  • Have you increased available RAM? (`-Xms` flag) – Daniel M. Jun 08 '15 at 11:10
  • @assylias Side note: Don't provide relevant information in comments; but to update question instead. Wow; cool; first time I am suggesting that to a person with 50 times my reputation (normally I only do that for people that have much less reputation than myself ;-) And yes, 50 seconds seems totally out of normal. – GhostCat Jun 08 '15 at 11:19
  • @DanielM. You meant `-Xmx`? – Axel Jun 08 '15 at 11:23
  • @DanielM. no change. – assylias Jun 08 '15 at 11:47
  • 2
    @TagirValeev Indeed I have found one class that increases the compile time by 25 seconds (see my edit)... – assylias Jun 08 '15 at 12:30
  • @JoopEggen I'm using the latest version of jOOQ (3.6.1) and I don't have any other versions imported by other dependencies. Also see my edit, one single line of code increases the compilation time by 25 seconds so it doesn't seem like this has to two with dependencies downloading... – assylias Jun 08 '15 at 12:45
  • That looks like a perfectly routine JOOQ query there. Do you see anything unusual in the resulting class file? How about `-g:none`, does that change things? – biziclop Jun 08 '15 at 13:28
  • @biziclop the resulting class file in this case is empty (looks like javac sees the method is unused and private so skips it and the class file only has the default constructor). – assylias Jun 08 '15 at 13:56
  • @biziclop making the method public makes no difference (in which case the content of the java class is very similar with the two versions of the code). Unless your comment was referring to my latest edit! – assylias Jun 08 '15 at 14:05
  • @assylias It was the latest edit, yes. :) This sounds more and more like a javac bug. I would guess the Eclipse compiler for example will have no problems compiling this class. – biziclop Jun 08 '15 at 14:22
  • 1
    [More workarounds and explanations can be seen here](http://stackoverflow.com/questions/34223249/slow-compilation-with-jooq-3-6-plain-sql-and-the-javac-compiler) – Lukas Eder Dec 11 '15 at 12:51

3 Answers3

9

Troubleshooting - general approach

You can start by recreating an empty project and add packages back one by one until the compilation time is affected - that should help you identify the package that is causing the problem.

You can then remove all classes in the package and add them back one by one - that should help you find the classes that cause the issue.

You can then remove all the methods from each of those classes and add them back one by one until you see the compilation time increase (you can save time by only recompiling that one class).

Specific cause

In this case it seems that the root cause is a bug in javac so I have filed a bug report which has been marked as a duplicate of "JEP 215: Tiered Attribution for javac" with a target to be fixed on Java 9.

In the meantime, the workaround is to introduce local variables when there are nested generic method calls that use generic type inference, but unfortunately that does not always work...

Community
  • 1
  • 1
assylias
  • 321,522
  • 82
  • 660
  • 783
  • So it wasn't anything specific to JOOQ or `having()` that caused the problem, simply the level of nesting did the damage. That's good to know. – biziclop Jun 10 '15 at 13:05
  • 1
    @biziclop JOOQ uses generics heavily so it probably contributed to the problem but the root cause is javac's new type inference system. – assylias Jun 10 '15 at 13:14
  • 2
    Sorry, that's what I meant, that it can affect any code that relies heavily on nested generic methods, Hamcrest for example. – biziclop Jun 10 '15 at 13:19
8

One not so well known feature of Java 8 is Generalized Target-Type Inference.

While it allows to write clearer code, this requires more work for Javac. Sometimes this results in exponential complexity of the type inference problem. This is a known issue, but unfortunately still unresolved - see JDK-8055984, JDK-8067767.

The workaround is to compile at Java 7-compatibility level: javac -source 7, or just to use simpler constructions.

apangin
  • 92,924
  • 10
  • 193
  • 247
  • Now, both [JDK-8055984](https://bugs.openjdk.java.net/browse/JDK-8055984) and [JDK-8067767](https://bugs.openjdk.java.net/browse/JDK-8067767) are closed. – Tokuhiro Matsuno May 16 '17 at 23:38
1

There was multiple discussions related to this. Adding these references in case anyone else stumbles upon this post.

Initial discussion:

In my case I essentially tried to use auto-generated code as much as possible. Alternatively you can try the suggestion that Lukas mentions in this StackOverflow post linked above.

Community
  • 1
  • 1
csgeek
  • 270
  • 3
  • 19