Frage

Ich versuche, über 100 Java -Klassen aus verschiedenen Paketen aus einem sauberen Verzeichnis (keine inkrementellen Kompilierungen) mit den folgenden Ameisenaufgaben zu kompilieren:

<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>

Wenn ich die Kompilierungsaufgabe jedoch zum ersten Mal ausführe, erhalte ich immer eine StackOverflowException.Wenn ich die Aufgabe erneut ausführe, führt der Compiler einen inkrementellen Build durch und alles funktioniert einwandfrei.Dies ist unerwünscht, da wir verwenden Tempomat einen automatischen täglichen Build durchzuführen, was zu falschen Build-Fehlern führt.

Als schnelle Lösung habe ich zwei separate Aufgaben erstellt und jeweils Teile des Projekts zusammengestellt.Ich glaube wirklich nicht, dass diese Lösung Bestand haben wird, da in Zukunft weitere Klassen hinzugefügt werden, und ich möchte nicht jedes Mal neue Kompilierungsaufgaben hinzufügen, wenn wir das „Kompilierungslimit“ erreichen.

War es hilfreich?

Lösung

Es wird schön sein zu wissen;Was kann während der Zusammenstellung von Java -Code einen Stackoverflowerror verursachen oder verursachen?

Es ist wahrscheinlich, dass die Auswertung des langen Ausdrucks in Ihrer Java-Datei viel Speicher verbraucht und da dies in Verbindung mit der Kompilierung anderer Klassen erfolgt, geht der VM einfach der Stapelspeicher aus.Ihre generierte Klasse überschreitet möglicherweise die gesetzlichen Grenzen für ihren Inhalt.Siehe Kapitel 4.10 Einschränkungen der Java Virtual Machine In Die Java Virtual Machine Specification, Zweite Ausgabe.

Lösung 1:Refaktorieren Sie die Klasse

Da Ihre Klasse gerade generiert wird, ist dies möglicherweise keine Option.Dennoch lohnt es sich, einen Blick auf die Optionen zu werfen, die Ihr Tool zur Klassengenerierung bietet, um zu sehen, ob es zu etwas weniger Ärgerlichem führen kann.

Lösung 2:Erhöhen Sie die Stapelgröße

Ich finde Kieron hat eine Lösung, wenn er das Argument -Xss erwähnt. javac akzeptiert eine Reihe nicht standardmäßiger Argumente, die je nach Version und Compiler-Anbieter variieren können.

Mein Compiler:

$ javac -version
javac 1.6.0_05

Um alle Optionen dafür aufzulisten, würde ich diese Befehle verwenden:

javac -help
javac -X
javac -J-X

ICH denken Das Stack-Limit für Javac beträgt standardmäßig 512 KB.Mit diesem Befehl können Sie die Stapelgröße für diesen Compiler auf 10 MB erhöhen:

javac -J-Xss10M Foo.java

Möglicherweise können Sie dies in einer Ant-Datei mit a übergeben Compilerarg Element in Ihrem verschachtelt javac Aufgabe.

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

Andere Tipps

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

von dem Kommentar oben ist falsch.Sie benötigen ein Leerzeichen zwischen -J und -X, etwa so:

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

um 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ültiges Flag:-J-XSS1M [Javac] Verwendung:javac

Versuchen Sie, einige Variationen dieser Attribute zum hinzuzufügen Ameise javac Aufgabe Linie:

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

Sie können es auch versuchen fork="true", Ich bin mir nicht sicher, ob Sie damit Werte für Stack und Heap festlegen können (auch bekannt als -Xm1024), aber es könnte hilfreich sein (wenn es über die Befehlszeile funktionieren würde, aber nicht in Ant).

[Bearbeiten]:Link hinzugefügt – der javac Aufgabe Die Seite scheint darauf hinzudeuten, dass die oben genannten Parameter auch von Ihnen festgelegt werden müssen fork="true".

Passiert das, wenn Sie den Befehl javac über die Befehlszeile ausführen?Vielleicht möchten Sie es versuchen Gabel Attribut.

Das ist ziemlich seltsam, 100 Unterrichtsstunden sind wirklich nicht viel.Was macht der Compiler, wenn der Stapel überläuft?Wird ein nützlicher Stacktrace generiert?Was passiert, wenn Sie rennen? javac direkt auf der Befehlszeile statt über Ant?

Eine mögliche Problemumgehung besteht darin, einfach die Größe des Stapels mithilfe von zu erhöhen -Xss Argument zur JVM;entweder zur laufenden JVM ant oder per Einstellung fork="true" und ein <compilerarg> auf der <javac> Aufgabe.Wenn ich darüber nachdenke, verschwindet das Problem tatsächlich, wenn ich nur das einsetze fork="true"?

Hier ist, was ich gefunden habe.Nachdem ich meine Frage gestellt hatte, änderte ich die Kompilierungsaufgabe mit den Attributen fork="true", memoryinitialsize="256m" Und memorymaximumsize="1024m" (Ich habe heute herausgefunden, dass dies von Kieron und jmanning2k vorgeschlagen wurde, vielen Dank für Ihre Zeit).Das Problem wurde dadurch jedoch nicht gelöst.

Ich habe beschlossen, Klassen aus dem Quellbaum zu entfernen, um zu sehen, ob das Problem lokalisiert werden kann.Es stellte sich heraus, dass wir eine Web-Service-Client-Klasse dafür hatten Achse 1.4 das automatisch aus einer WSDL-Datei generiert wurde.Nun ist diese Klasse ein Monster (wie in Frankenstein), sie hat 167 Feldmitglieder (alle vom Typ String), 167 Getter/Setter-Paare (1 für jedes Feld), einen Konstruktor, der alle 167 Felder als Parameter empfängt, und equal-Methode, die alle 167 Felder auf seltsame Weise vergleicht.Für jedes Feld sieht der Vergleich folgendermaßen aus:

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

Das Ergebnis dieses Vergleichs wird mit dem Ergebnis des Vergleichs des nächsten Felds „und-verknüpft“ (&&) und so weiter.Die Klasse fährt mit einer hashCode-Methode fort, die auch alle Felder verwendet, einigen benutzerdefinierten XML-Serialisierungsmethoden und einer Methode, die ein Axis-spezifisches Metadatenobjekt zurückgibt, das die Klasse beschreibt und das auch alle Feldmitglieder verwendet.

Diese Klasse wird nie geändert, daher habe ich einfach eine kompilierte Version in den Klassenpfad der Anwendung eingefügt und das Projekt ohne Probleme kompiliert.

Jetzt weiß ich, dass das Problem durch Entfernen dieser einzelnen Quelldatei gelöst wurde.Allerdings habe ich absolut keine Ahnung, warum diese spezielle Klasse das Problem verursacht hat.Es wird schön sein zu wissen;Was kann einen StackOverflowError beim Kompilieren von Java-Code verursachen oder verursachen?Ich denke, ich werde diese Frage posten.

Für Interessierte:

  • Windows XP SP2
  • SUNs JDK 1.4.2_17
  • Ameise 1.7.0
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top