Question

J'ai un projet Java Maven avec environ 800 fichiers sources (dont certains résultent javacc / JTB) qui prend un bon 25 minutes pour compiler avec javac.

Quand j'ai changé mon pom.xml sur d'utiliser le compilateur Eclipse, il faut environ 30 secondes pour compiler.

Toutes les suggestions pour lesquelles javac (1,5) est en cours d'exécution si lentement? (Je ne veux pas passer à le compilateur Eclipse de façon permanente, comme le plug-in pour Maven semble plus un peu buggé.)

J'ai un test qui reproduit facilement le problème. Le code suivant génère un certain nombre de fichiers source dans le package par défaut. Si vous essayez de compiler ImplementingClass.java avec javac, il semble faire une pause pendant un temps excessivement long.

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();
    }
}
Était-ce utile?

La solution

Vous obtenez le même comportement avec JDK 1.6, y compris la mise à jour 14, la construction 04, en utilisant G1 ne change pas le comportement, (bien que G1 semble fonctionner très bien).

Surveillance javac avec jvisualvm, décharges de fil répétés montrent les principaux lots de dépenses de fil de temps en

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)

et barattage à travers un grand nombre de courts cas vécues ces classes:

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

Je suppose que le code est barattage par com.sun.tools.javac.comp.Check.checkCompatibleConcretes comparant chaque méthode avec toutes les autres méthodes

La javadoc de cette méthode:

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

Il peut être le compilateur de cette éclipse, soit ne pas effectuer cette vérification, ou ne pas effectuer de la même façon.

Autres conseils

Sun m'a confirmé par courriel que c'est un nouveau bug ( 6827648 dans leur base de données de bogue).

Il se peut que le compilateur javac fonctionne près de sa limite de segment de mémoire (64 Mo ou plus). Dans ce cas, il passe la plupart du temps dans le collecteur des ordures. Donnez au compilateur une bonne partie de la mémoire, par exemple 256M ou 512M et voir si elle tourne plus vite.

Le fait que vous utilisez source généré, massif différence de vitesse et le StackOverflowError pourrait suggérer que l'un (ou plusieurs) de vos fichiers ont des constructions que les parseurs javac ne sont pas d'accord avec.

Pouvez-vous essayer de compiler des sous-ensembles seulement de votre code et voir si une classe / package ralentit le processus en particulier (probablement l'un de ceux générés).

Pour le compilateur Sun vous commencez un processus tout en JVM pour chaque fichier que vous souhaitez compiler. Pour le compilateur Eclipse il est simplement connecté à un processus démon. Je recommande la création fourchette à false, même si elle peut encore ne pas être aussi rapide.

Peut-être la construction Eclipse est que la compilation source modifiée. Qu'est-ce qui se passe si vous compilez dans Eclipse après un nettoyage?

Je ne sais pas comment Maven appelle le compilateur, mais les chiffres de performance que vous mentionnez suggèrent que javac est exécuté dans son propre processus / VM comme cela a déjà suggéré dans une autre réponse. En commençant un nouveau processus / VM pour chaque fichier que vous compilez est très coûteux, vous devez vous assurer de configurer le compilateur d'utiliser la machine virtuelle que vous pourriez avoir alreay. Je sais que ANT offre, mais je ne l'ai pas utilisé moi-même Maven. Compte tenu du fait qu'il est populaire, je doute qu'il manque une caractéristique importante cependant.

Je pense que quelque chose comme ce qui suit passe: fourches Maven javac, processus JVM pour les étapes distinctes dans son cycle de vie: Maven Build-cycle de vie

Eclipse exécute généralement sa compilation en arrière-plan (sur Enregistrer), de sorte que l'étape sera ajoutée à la phase de compilation. S'il y a des dépendances importantes, c'est là que vous perdez le débit.

En plus (selon la configuration mvn) chaque méthode de test obtient sa propre machine virtuelle Java. Depuis le passage de test est un pré-req à la phase de l'emballage, il est possible que vous perdez du temps à vos exécutions de test JUnit (en particulier si elles sont des tests de fonctionnement lents). Ceci est seulement un coupable probable si vous avez beaucoup de code de test dans votre arbre source.

Très probablement de tous, votre classe ne des quantités importantes de fichier E / S, de sorte que est une zone d'opportunité. Il semble que votre boucle est en cours d'exécution 1000 fois par événement de découverte du fichier signifie 800 * 1000 = 800.000 créations PrintStream dans le corps de la boucle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top