【问题标题】:Why is javac 1.5 running so slowly compared with the Eclipse compiler?为什么 javac 1.5 与 Eclipse 编译器相比运行如此缓慢?
【发布时间】:2010-10-15 18:03:07
【问题描述】:

我有一个 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();
    }
}

【问题讨论】:

  • 尝试生成 SSCCE (sscce.org) 并向 Sun (bugs.sun.com) 提交错误报告。特别是因为您已经将问题减少到一个非常具体的案例。
  • 您使用的是什么操作系统?这对我来说很快……在 OS X 上。
  • 这是在 Windows XP 和 Windows Server 2003 上
  • 你是在命令行上用javac还是在eclipse或maven中编译了上面的代码?如果不是 javac 本身,请尝试一下,看看它是否有相同的减速。只是为了消除 maven/eclipse 作为一个问题。
  • 我记得几年前发生的另一件事是,我们使用的防病毒软件被配置为检查文件的每次访问,这会导致性能下降。可能是 eclipse 编译器将文件内容缓存在内存中,而 javac 没有,并且某些东西减慢了文件访问速度。

标签: java eclipse maven-2 javac


【解决方案1】:

Sun 已通过电子邮件向我确认这是一个新错误(6827648 在他们的错误数据库中)。

【讨论】:

    【解决方案2】:

    您在 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 将每个方法与其他所有方法进行比较

    那个方法的javadoc:

    /** Check that a class does not inherit two concrete methods
     *  with the same signature.
     */
    

    可能是 Eclipse 的编译器要么不执行该检查,要么不以相同的方式执行它。

    【讨论】:

      【解决方案3】:

      可能是 javac 编译器在其堆限制(64MB 左右)附近运行。在这种情况下,它大部分时间都在垃圾收集器中。给编译器一大块内存,比如 256M 或 512M,看看它是否运行得更快。

      【讨论】:

      • 除非另外配置,maven-compiler-plugin 在进程内运行 javac。 simonn 尝试的一个可能的修复方法是将 MAVEN_OPTS 环境变量设置为“-Xms128M Xmx512M”左右。如果插件配置了fork=true,他可以使用meminitial和maxmem参数来控制这个。
      • 我试过运行“javac -verbose -J-Xms512m -J-Xmx1024m ImplementingClass.java”,问题依旧。
      【解决方案4】:

      您使用生成的源代码这一事实、巨大的速度差异和StackOverflowError 可能表明您的一个(或多个)文件具有javac 解析器的某些结构不同意。

      您能否尝试只编译代码的子集,看看是否有任何一个类/包会减慢进程,尤其是(可能是生成的类/包之一)。

      【讨论】:

      • 我现在尝试将项目拆分为两个 - 由 javacc/jtb 生成的 391 个文件和 373 个手动编码的文件。绝大部分时间都花在了手工编码的编译上(编译生成的大约需要 18 秒)
      • 有趣,我没想到。我会越来越多地拆分源文件,以尝试找出是否有几个文件导致速度变慢。
      • 另一个提示:使用“strace -eopen ant”运行您的构建。每次打开文件时都会打印出来。等待巨大的输出流中的暂停并检查之前打开的最后一个文件名。应该给你一个体面的提示。
      【解决方案5】:

      对于 Sun 编译器,您正在为要编译的每个文件启动一个完整的 JVM 进程。对于 Eclipse 编译器,它只是连接到一个守护进程。我建议将 fork 设置为 false,尽管它可能仍然没有那么快。

      【讨论】:

      • 25 分钟/80 个源文件 = 每个 javac 18.75 秒。如果对于每个源文件,它必须加载大量 jars/classes,则可能。
      • 感谢您的建议 - 我试过了,但遗憾的是编译时间没有明显差异。
      【解决方案6】:

      也许 Eclipse 构建只是编译修改后的源代码。如果你在清理之后在eclipse中编译它会发生什么?

      【讨论】:

      • 在这两种情况下,我在“mvn install”之前都做了一个“mvn clean”。
      【解决方案7】:

      我不知道 maven 如何调用编译器,但您提到的性能数字表明 javac 是在它自己的进程/VM 中执行的,正如另一个答案中已经建议的那样。由于为您编译的每个文件启动一个新进程/VM 的成本非常高,您需要确保将编译器配置为使用您可能已经拥有的 VM。我知道 ANT 提供了,但我自己没有使用过 maven。鉴于它很受欢迎,我怀疑它缺少如此重要的功能。

      【讨论】:

        【解决方案8】:

        我认为正在发生以下情况:Maven forks javac,JVM 进程在其生命周期中的不同步骤:Maven Build Life-cycle

        Eclipse 通常在后台(保存时)运行其编译,因此该步骤将被添加到编译阶段。如果存在大量依赖关系,这就是您失去吞吐量的地方。

        此外(取决于 mvn 配置)每个测试方法都有自己的 JVM。由于测试通道是打包阶段的先决条件,因此您可能会浪费时间执行 JUnit 测试(特别是如果它们是运行缓慢的测试)。如果您的源代码树中有大量测试代码,这可能是罪魁祸首。

        最有可能的是,您的班级执行了大量的文件 I/O,因此这是一个机会领域。看起来您的循环在每个文件发现事件中执行 1000 次,这意味着在循环主体中创建了 800*1000 =800,000 个 PrintStream。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-04
          • 2021-01-16
          • 2011-08-22
          相关资源
          最近更新 更多