2008-08-19 5 views
4

Ich versuche, über 100 Java-Klassen aus verschiedenen Paketen von einem sauberen Verzeichnis (keine inkrementelle compiliert) mit den folgenden ant Aufgaben zu kompilieren:Ant <javac> Aufgaben werfen Stackoverflow

<target name="-main-src-depend"> 
    <depend srcdir="${src.dir}" 
      destdir="${bin.dir}" 
      cache="${cache.dir}" 
      closure="true"/> 
</target> 

<target name="compile" depends="-main-src-depend" 
     description="Compiles the project."> 

    <echo>Compiling</echo> 

    <javac target="${javac.target}" 
      source="${javac.source}" 
      debug="${javac.debug}" 
      srcdir="${src.dir}" 
      destdir="${bin.dir}"> 
     <classpath> 
      <path refid="runtime.classpath"/> 
      <path refid="compile.classpath"/> 
     </classpath> 
    </javac> 
</target> 

jedoch das erste Mal, dass ich Führen Sie die Kompilierungsaufgabe Ich bekomme immer eine StackOverflowException. Wenn ich den Task erneut ausführe, führt der Compiler einen inkrementellen Build durch und alles funktioniert einwandfrei. Dies ist unerwünscht, da wir CruiseControl verwenden, um eine automatische tägliche Erstellung durchzuführen, was zu falschen Build-Fehlern führt.

Als schnelle und unsaubere Lösung I 2 separate Aufgaben erstellt haben, Teile des Projekts in jeder Zusammenstellung. Ich glaube wirklich nicht, dass diese Lösung halten wird, da in Zukunft weitere Klassen hinzugefügt werden, und ich möchte nicht jedes Mal neue Kompilieraufgaben hinzufügen, wenn wir das "Kompilierlimit" erreichen.

+1

Es wirft eine StackOverflowException - so dass Sie uns die Schuld geben? :-) – kenj0418

+0

@ kenj0418 - Dein Kommentar hat mich wirklich am Kopf kratzen lassen, bis ich den Smiley sah. Gute! –

Antwort

4

It will be nice to know; what can cause or causes a StackOverflowError during compilation of Java code?

Es ist wahrscheinlich, dass die Bewertung der lang Ausdruck in Ihre Java-Datei verbraucht viel Speicher und da dies in Verbindung mit der Kompilierung anderer Klassen geschieht, wird die VM einfach ausgeführt s aus dem Stapelspeicher. Ihre generierte Klasse verschiebt möglicherweise die gesetzlichen Grenzen für ihren Inhalt. Siehe Kapitel 4.10 Limitations of the Java Virtual Machine in The Java Virtual Machine Specification, Second Edition.

Fix 1: Refactoring der Klasse

Da Ihre Klasse erzeugt wird, könnte dies nicht eine Option sein. Dennoch lohnt es sich, die Optionen zu betrachten, die Ihr Klassengenerierungswerkzeug bietet, um zu sehen, ob es etwas weniger Ärgerhaftes erzeugen kann.

Fix 2: erhöhen die Stapelgröße

Ich denke Kieron eine Lösung hat, wenn er das -Xss Argument erwähnt. javac erfordert eine Reihe von Nicht-Standardargumenten, die zwischen Versionen und Compiler-Anbietern variieren können.

Mein Compiler:

$ javac -version 
javac 1.6.0_05 

Um alle Optionen für Sie zusammengestellt, ich diese Befehle verwenden würde:

javac -help 
javac -X 
javac -J-X 

ich denken der Stapelgrenze für javac ist 512Kb standardmäßig. Sie können mit diesem Befehl die Stapelgröße für diesen Compiler zu 10Mb erhöhen:

javac -J-Xss10M Foo.java 

Möglicherweise können Sie mit einem Elemente compilerarg in Ihrer Javac Aufgabe verschachtelt dieses in einer Ant-Datei zu übergeben.

<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true"> 
    <compilerarg value="-J-Xss10M" /> 
</javac> 
+0

Der letzte Teil dieser Antwort wird einen Fehler von javac ergeben. Bitte sehen Sie diese Antwort: http://StackOverflow.com/Questions/16935/ants-Javac-Tasks-Throws-StackOverflowException/1042236#1042236 – npellow

+0

Das Hinzufügen eines Speicherplatzes verursacht diesen Fehler mit Sun javac 1.6.0_05 auf WinXP: "java.lang .NoClassDefFoundError: -Xss10M "... Ich vermute, dass dies compilerabhängig sein muss. – McDowell

1

Geschieht dies, wenn Sie den javac Befehl von der Kommandozeile ausführen? Möglicherweise möchten Sie das fork Attribut versuchen.

1

versuchen, einige Variation dieser Attribute in die Ant javac task Zeile hinzufügen:

memoryinitialsize="256M" memorymaximumsize="1024M" 

Sie auch fork="true" versuchen, nicht sicher, ob dies erlaubt Ihnen Werte für Stack und Heap zu setzen (aka -Xm1024), aber es kann helfen (wenn es von der Befehlszeile funktionieren würde, aber nicht in Ant).

[Bearbeiten]: Link hinzugefügt - die javac task Seite würde scheinen, dass die obigen Parameter erfordern, dass Sie auch fork="true" setzen.

0

Das ist ziemlich merkwürdig, 100 Klassen sind wirklich nicht so viele. Was macht der Compiler, wenn der Stack überläuft? Wird eine nützliche Stack-Trace generiert? Was passiert, wenn Sie javac direkt in der Befehlszeile anstelle von thorugh ant ausführen?

Eine mögliche Abhilfe ist, einfach die Größe des auf die JVM mit dem -Xss Argumente Stapels zu erhöhen; entweder auf die JVM läuft ant oder durch fork="true" und <compilerarg> auf der <javac>-Aufgabe. Jetzt, wo ich darüber nachdenke, verschwindet das Problem, indem ich einfach die fork="true" einfüge?

0

Hier ist was ich gefunden habe. meine Frage Nach der Veröffentlichung ging ich auf und modifiziert, um die Kompilierung Aufgabe mit den Attributen fork="true", memoryinitialsize="256m" und memorymaximumsize="1024m" (ein heute gefunden, dass dies durch Kieron und jmanning2k vorgeschlagen wurde, vielen Dank für Ihre Zeit). Dies hat das Problem dennoch nicht gelöst.

entschied ich mich zu entfernen Klassen aus dem Quellbaum zu beginnen, um zu sehen, ob ein das Problem lokalisieren kann. Es stellte sich heraus, dass wir eine Web-Service-Client-Klasse für Axis 1.4 hatten, die automatisch aus einer WSDL-Datei generiert wurde. Nun, diese Klasse ist ein Monster (wie in Frankenstein), es hat 167 Feldmitglieder (alle vom Typ String), 167 Getter/Setter-Paare (1 für jedes Feld), einen Konstruktor, der alle 167 Felder als Parameter erhält, ein equals-Methode, die alle 167 Felder auf eine seltsame Weise vergleicht. Für jedes Feld geht der Vergleich wie folgt aus:

(this.A == null && other.getA() == null) || (this.A != null && this.A.equals(other.getA())) 

Das Ergebnis dieses Vergleichs ist „anded“ (& &) mit dem Ergebnis des Vergleichs des nächsten Feldes, und so weiter.Die Klasse setzt eine hashCode-Methode fort, die auch alle Felder, einige benutzerdefinierte XML-Serialisierungsmethoden und eine Methode verwendet, die ein Axis-spezifisches Metadatenobjekt zurückgibt, das die Klasse beschreibt und das auch alle Feldmitglieder verwendet.

Diese Klasse wird nie geändert, also habe ich nur eine kompilierte Version in den Klassenpfad der Anwendung geschrieben und das Projekt ohne Probleme kompiliert.

Jetzt weiß ich, dass das Entfernen dieser einzelnen Quelldatei das Problem gelöst hat. Ich habe jedoch keine Ahnung, warum diese spezielle Klasse das Problem verursacht hat. Es wird nett sein zu wissen; was kann einen StackOverflowError beim Kompilieren von Java-Code verursachen oder verursachen? Ich denke, ich werde diese Frage stellen.

Für Interessenten:

  • Windows XP SP2
  • Suns JDK 1.4.2_17
  • Ant 1.7.0
1
<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true"> 
     <compilerarg value="-J-Xss10M" /> 
    </javac> 

vom comment above ist falsch.Sie benötigen einen Raum zwischen dem -J und -X, etwa so:

<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true"> 
    <compilerarg value="-J -Xss10M" /> 
</javac> 

den folgenden Fehler zu vermeiden:

[javac] 
[javac] The ' characters around the executable and arguments are 
[javac] not part of the command. 
[javac] Files to be compiled: 

... [Javac] javac: ungültige Flagge: -J- Xss1m [javac] Usage: javac