Java 解决编译速度慢的问题

Java 解决编译速度慢的问题,java,performance,compilation,javac,Java,Performance,Compilation,Javac,我应该如何调查和排除编译速度慢的问题 我的项目大约有100个类,编译需要45秒以上,这对我来说非常缓慢。作为参考,我有另一个项目,它有50个类,可以在3秒内编译 附言: 我使用maven作为构建工具。编译需要50秒(mvn clean compile),其中45秒用于运行javac(通过运行-X选项确认) 增加内存量没有帮助(-Xms500m) 我可以提供更多关于我的项目的信息,但这是相当标准的,所以我不确定什么信息是相关的 更新 多亏了塔吉尔的主意,我终于找到了其中一个罪犯。该类将编译时

我应该如何调查和排除编译速度慢的问题

我的项目大约有100个类,编译需要45秒以上,这对我来说非常缓慢。作为参考,我有另一个项目,它有50个类,可以在3秒内编译

附言:

  • 我使用maven作为构建工具。编译需要50秒(
    mvn clean compile
    ),其中45秒用于运行javac(通过运行
    -X
    选项确认)
  • 增加内存量没有帮助(
    -Xms500m
  • 我可以提供更多关于我的项目的信息,但这是相当标准的,所以我不确定什么信息是相关的

更新 多亏了塔吉尔的主意,我终于找到了其中一个罪犯。该类将编译时间增加20秒:

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));
  }
}
import org.jooq.DSLContext;
导入org.jooq.Field;
导入静态org.jooq.impl.DSL.field;
导入静态org.jooq.impl.DSL.round;
导入静态org.jooq.impl.DSL.sum;
课堂测试{
静态对象快速(DSLContextSQL){
字段a=字段(“a”).cast(双类);
返回sql.select()
.具有(四舍五入(和(a)型(双级),2)ne(0d));
}
静态对象速度慢(DSLContext sql){
返回sql.select()
具有(四舍五入(总和(字段(“a”).cast(双类)).cast(双类)).2.ne(0d));
}
}

如果注释掉了
slow
方法,编译时间将恢复正常。

Java 8的一个不太为人所知的特性是

虽然它允许编写更清晰的代码,但对于
Javac
,这需要做更多的工作。有时这会导致类型推理问题的指数复杂性。这是一个已知的问题,但不幸的是仍未解决-请参阅

解决方法是在Java 7兼容级别编译:
javac-source 7
,或者只使用更简单的构造。

故障排除-一般方法 您可以从重新创建一个空项目开始,然后逐个添加包,直到编译时间受到影响—这将有助于您识别导致问题的包

然后,您可以删除包中的所有类,并逐个将它们添加回去—这将有助于您找到导致问题的类

然后,您可以从每个类中删除所有方法,并逐个添加它们,直到您看到编译时间增加为止(您可以通过以下方式节省时间)

具体原因 在本例中,根本原因似乎是javac中的一个bug,因此我提交了一个文件,该文件被标记为的副本,目标是在java9上修复


同时,解决方法是在存在使用泛型类型推断的嵌套泛型方法调用时引入局部变量,但不幸的是,这并不总是有效的…

有多个与此相关的讨论。添加这些参考资料,以防其他人偶然发现这篇文章

初步讨论:


在我的例子中,我基本上尽量使用自动生成的代码。或者,您可以尝试Lukas在上面链接的StackOverflow帖子中提到的建议。

您是否尝试过使用
-X
标志进行构建,这将为您提供一个依赖项报告您的项目中是否有自动生成的类?您是否尝试过部分地重新编译它(例如,手动删除属于一半包的类文件,重新编译并测量时间)以缩小问题的范围?有可能一个或多个类会减慢整个过程。@KennethClark使用-X显示传递给javac的参数,然后挂起45秒,然后打印“构建成功”…@TagirValeev确实我发现了一个类,它将编译时间增加了25秒(请参阅我的编辑)…因此,造成问题的并不是JOOQ或
having()
,只是嵌套级别造成了损害。这很好。@biziclop JOOQ大量使用泛型,因此可能是导致问题的原因,但根本原因是javac的新类型推理系统。对不起,这就是我的意思,它可能会影响任何严重依赖嵌套泛型方法的代码,例如Hamcrest。现在,和都关闭了。