代码之家  ›  专栏  ›  技术社区  ›  Simon Nickerson

为什么JavaC1.5与Eclipse编译器相比运行得如此缓慢?

  •  8
  • Simon Nickerson  · 技术社区  · 17 年前

    我有一个JavaMaven项目,其中包含大约800个源文件(一些由javacc/JTB生成),使用javac编译需要25分钟。

    当我将pom.xml改为使用Eclipse编译器时,编译大约需要30秒。

    关于为什么javac(1.5)运行得这么慢,有什么建议吗?(我不想永久地切换到Eclipse编译器,因为Maven的插件似乎有点问题。)

    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();
        }
    }
    
    8 回复  |  直到 16 年前
        1
  •  7
  •   Simon Nickerson    17 年前

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

        2
  •  6
  •   Stephen Denne    17 年前

    JDK1.6也有同样的行为,包括更新14,构建04,使用G1不会改变行为(尽管G1看起来工作得很好)。

    使用jvisualvm监视javac时,重复的线程转储显示主线程在Java中花费了大量时间

    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
  •  5
  •   Ingo    17 年前

        4
  •  2
  •   Joachim Sauer    17 年前

    事实上,您正在使用生成的源 速度和速度的差异 StackOverflowError javac

        5
  •  1
  •   Tom Hawtin - tackline    17 年前

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

        6
  •  0
  •   Jack BeNimble    17 年前

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

        7
  •  0
  •   lothar    17 年前

        8
  •  0
  •   jasonnerothin    17 年前

    我认为如下情况正在发生:Maven分叉javac,JVM在其生命周期中为单独的步骤处理过程: Maven Build Life-cycle

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

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