Frage

Ich habe ein Java-Maven-Projekt mit über 800 Quelldateien (einige, die von javacc / JTB), die eine gute 25 Minuten nimmt mit javac zu kompilieren.

Wenn ich meine pom.xml geändert über die Eclipse-Compiler zu verwenden, dauert es etwa 30 Sekunden zu kompilieren.

Irgendwelche Vorschläge, warum javac (1.5) so langsam läuft? (Ich möchte nicht permanent mit den Eclipse-Compiler wechseln, da das Plugin für Maven scheint mehr als nur ein wenig fehlerhaft.)

Ich habe einen Testfall, der leicht das Problem reproduziert. Der folgende Code erzeugt eine Reihe von Quelldateien im Standard-Paket. Wenn Sie versuchen, ImplementingClass.java mit javac zu kompilieren, wird es scheinen, für eine übermäßig lange Zeit zu unterbrechen.

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();
    }
}
War es hilfreich?

Lösung

Sie erhalten das gleiche Verhalten mit JDK 1.6, einschließlich Update 14, 04 bauen, G1 verwenden das Verhalten nicht ändern, (obwohl G1 wirklich gut zu funktionieren scheint).

Monitoring javac mit jvisualvm zeigen wiederholt Thread-Dumps der Haupt-Thread die Ausgaben viel Zeit in

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)

und am laufenden Band durch eine große Anzahl von kurzen Dauer Instanzen dieser Klassen:

com.sun.tools.javac.code.Types$Subst
com.sun.tools.javac.util.List
com.sun.tools.javac.code.Types$MethodType

Ich vermute, dass der Code am laufenden Band durch com.sun.tools.javac.comp.Check.checkCompatibleConcretes jede Methode mit jedem anderen Verfahren vergleichen

Diese Methode des javadoc:

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

Es kann, die Eclipse-Compiler entweder nicht, dass der Check nicht durchführt oder nicht durchführt es nicht in der gleichen Art und Weise.

Andere Tipps

Sun hat per E-Mail zu mir bestätigt, dass dies ein neuer Bug ( 6827648 in ihrer Bug-Datenbank).

Es kann sein, dass der javac-Compiler an seinem Haufen Grenze (64 MB oder so) in der Nähe arbeitet. In diesem Fall verbringt er die meiste Zeit in der Garbage Collector. Geben Sie den Compiler einen guten Teil des Speichers, sagen 256M oder 512M und sehen, ob es schneller läuft.

Die Tatsache, dass Sie erzeugt Quelle verwenden, die massiv Unterschied in der Geschwindigkeit und der StackOverflowError könnte, dass ein (oder mehrere) vorschlagen Ihrer Dateien einige Konstrukte haben, dass die javac Parsern nicht einverstanden mit.

Könnte versuchen Sie nur Teilmengen von Code zu kompilieren und sehen, ob eine Klasse / Paket, um den Prozess vor allem verlangsamt (wahrscheinlich eines der erzeugten sind).

Für die Sun-Compiler Sie Starten Sie einen ganzen JVM-Prozess für jede Datei wollen kompilieren. Für den Eclipse-Compiler verbindet es nur an einen Dämon-Prozess. Ich schlage vor, fork auf false setzen, obwohl es noch nicht ganz so schnell sein kann.

Vielleicht ist das Eclipse-Build nur kompiliert modifizierte Quelle. Was passiert, wenn Sie es in Eclipse nach einem sauberen kompilieren?

Ich weiß nicht, wie Maven ruft den Compiler, aber die Performance-Zahlen Sie deuten darauf hin, erwähnen, dass javac in einem eigenen Prozess ausgeführt wird / VM, wie bereits in einer anderen Antwort vorgeschlagen. Als Ausgangs könnte alreay haben einen neuen Prozess / VM für jede Datei, die Sie kompilieren ist sehr teuer Sie den Compiler zu konfigurieren, um sicherzustellen, müssen Sie die VM zu verwenden. Ich weiß, ANT bietet das, aber ich habe nicht verwendet mich maven. In Anbetracht der Tatsache, dass es populär Ich bezweifle, dass es zwar ein so wichtiges Merkmal fehlt.

Ich denke, in etwa wie folgt vorgeht: Maven Gabeln javac, JVM-Prozesse für getrennte Schritte in seinem Lebenszyklus: Maven Build-Lebenszyklus

Eclipse-Regel läuft seine Kompilierung im Hintergrund (auf Save), so wird dieser Schritt in der Kompilierung Phase hinzugefügt werden. Wenn es erhebliche Abhängigkeiten sind, ist dies, wo Sie Durchsatz sind zu verlieren.

Darüber hinaus (je nach Konfiguration MVN) jede Testmethode erhält eine eigene JVM. Da Testdurchgang ein Pre-req zum Paket Phase ist, ist es möglich, dass Sie Zeit, um Ihre JUnit Testausführungen sind zu verlieren (vor allem, wenn sie langsam laufenden Tests sind). Dies ist nur ein wahrscheinlicher Täter, wenn Sie eine Menge von Test-Code in Ihrem Quellbaum haben.

Die meisten wahrscheinlich von allen, Ihre Klasse hat erhebliche Mengen von Datei-I / O, das ist also ein Bereich der unbegrenzten Möglichkeiten. Es sieht aus wie Ihre Schleife ist 1000-mal pro Datei Entdeckung Ereignis Ausführung bedeutet 800 * 1000 = 800.000 Print Kreationen im Körper der Schleife.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top