2009-03-26 7 views
8

私は約800のソースファイル(javacc/JTBによって生成されたもの)を持つJava Mavenプロジェクトを持っています。これはjavacでコンパイルするのに25分ほどかかるものです。javac 1.5の実行速度がEclipseコンパイラと比べて遅いのはなぜですか?

Eclipseコンパイラを使用するようにpom.xmlを変更したとき、コンパイルに約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(); 
    } 
} 
+1

SSCCE(http://sscce.org/)の作成を試み、Sun(http://bugs.sun.com/)にバグレポートを提出してください。特に、あなたはすでに問題をかなり特殊なケースに減らしているからです。 –

+0

あなたはどのOSを使用していますか?それは私にとって高速です... OS Xで – TofuBeer

+0

これはWindows XPとWindows Server 2003にあります –

答えて

6

アップデート14、ビルド04など、JDK 1.6と同じ動作をしますが、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 

Iコードがcom.sun.tools.javac.comp.Check.checkCompatibleConcretesの各メソッドと他のすべてのメソッドを比較していると思われる

そのメソッドのjavadoc:

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

エクリプスのコンパイラがそのチェックを実行していないか、同じ方法で実行していない可能性があります。

0

多分、Eclipseビルドは変更されたソースをコンパイルするだけです。あなたがきれいな後にEclipseでコンパイルするとどうなりますか?

+0

どちらの場合も、 'mvn install'の前に 'mvn clean'を実行しました。 –

1

Sunコンパイラでは、コンパイルする各ファイルに対してJVMプロセス全体を起動します。 Eclipseコンパイラの場合、デーモンプロセスに接続するだけです。私はフォークをfalseに設定することをお勧めしますが、まだそれほど高速ではないかもしれません。

+0

それは25分の違いを作りますか?私はそうは思わないでしょう... –

+0

javacごとに25分/ 80ソースファイル= 18.75秒。ソースファイルごとにjars/classesのshedloadをロードしなければならない場合は可能です。 –

+0

あなたの提案をありがとう - 私はそれを試しましたが、残念ながらそれはコンパイル時に顕著な違いはありませんでした。 –

2

あなたが生成されたソースを使用しているという事実は、高速で大規模なStackOverflowErrorは、あなたのファイルがjavacパーサは一致しないことをいくつかの構成要素を持っているの1つ(またはそれ以上)を提案するかもしれません。

コードのサブセットのみをコンパイルし、いずれかのクラス/パッケージがプロセスを遅くするかどうか(特に生成されたものの1つ)を参照してください。

+0

私はjavacc/jtbによって生成された2つのファイル391と手作業でコード化された373でプロジェクトを分割しようとしました。大部分の時間は、手でコード化されたものをコンパイルするのに費やされます(生成されたものをコンパイルするのに約18秒かかりました)。 –

+0

興味深いことに、私はそれを推測しませんでした。私はさらにいくつかのファイルが遅い原因であるかどうかを調べるために、さらにソースファイルを分割します。 –

+0

別のヒント: "strace -eopen ant"を使ってビルドを実行してください。これは、ファイルが開かれるたびに出力されます。その巨大な出力ストリームで一時停止を待ってから、最後に開いたファイル名を確認してください。あなたにまともなヒントを与える必要があります。 –

5

javacコンパイラがヒープリミット(64MB程度)で動作している可能性があります。その場合、ほとんどの時間はガベージコレクタに費やされます。コンパイラにメモリの良い塊、たとえば256Mまたは512Mを与え、それがより速く実行されるかどうかを確認します。

+0

特に設定しない限り、maven-compiler-pluginはjavacのインプロセスを実行します。 simonnが試みる可能性のある修正は、MAVEN_OPTS環境変数を "-Xms128M Xmx512M"程度に設定することです。 プラグインがfork = trueに設定されている場合は、meminitialおよびmaxmemパラメータを使用してこれを制御できます。 – Barend

+0

私は "javac -verbose -J-Xms512m -J-Xmx1024m ImplementingClass.java"を実行しようとしても問題は解決しません。 –

0

私はMavenがコンパイラをどのように呼び出すのか分かりませんが、あなたが言及しているパフォーマンス番号はjavacがそれ自身のプロセス/ VMで実行されていることを示唆しています。コンパイルするすべてのファイルに対して新しいプロセス/ VMを開始するには、非常にコストがかかります。必要なVMを使用するようにコンパイラを設定する必要があります。私はANTがそれを提供していることを知っていますが、私はmavenを自分で使っていません。それが普及しているという事実を考えると、私はそのような重要な機能が欠けているとは思わない。

0

私は次のように起こっているようなものだと思う:Mavenのフォークのjavac、そのライフサイクルにおける個別のステップのためのJVMプロセス:Maven Build Life-cycle

Eclipseは通常、そのステップので、(保存上の)バックグラウンドでのコンパイルを実行しますコンパイルフェーズに追加されます。実質的な依存関係がある場合、これがスループットを失う場所です。

さらに、(mvnの設定に応じて)各テストメソッドはそれぞれ独自のJVMを取得します。テストの実行はパッケージ段階の前提条件であるため、JUnitのテスト実行に時間を浪費している可能性があります(特にテストが遅い場合)。あなたがソースツリーにたくさんのテストコードを持っていれば、これはおそらく唯一の原因です。

ほとんどの場合、クラスはかなりの量のファイルI/Oを実行するため、その可能性があります。あなたのループは、ファイル発見イベントごとに1000回実行されているようで、ループの本体に800 * 1000 = 800,000のPrintStream作成を意味します。

7

Sunは電子メールで、これが新しいバグ(バグデータベースに6827648)であることを確認しています。

関連する問題