Domanda

Sto cercando di compilare oltre 100 classi Java da pacchetti diversi da una directory pulita (nessuna compilazione incrementale) usando le seguenti attività di formiche:

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

Tuttavia, la prima volta che eseguo l'attività di compilazione ottengo sempre un'eccezione StackOverflowException.Se eseguo nuovamente l'attività, il compilatore esegue una compilazione incrementale e tutto funziona correttamente.Questo è indesiderabile dal momento che stiamo usando Regolazione automatica della velocità per eseguire una compilazione giornaliera automatica e ciò causa falsi errori di compilazione.

Come soluzione rapida e sporca ho creato 2 attività separate, compilando parti del progetto in ciascuna.Non penso davvero che questa soluzione sarà valida man mano che verranno aggiunte più classi in futuro e non voglio aggiungere nuove attività di compilazione ogni volta che raggiungiamo il "limite di compilazione".

È stato utile?

Soluzione

Sarà bello saperlo;Cosa può causare o causare un stackoverflowerror durante la compilazione del codice Java?

È probabile che la valutazione dell'espressione lunga nel file Java consumi molta memoria e poiché questa operazione viene eseguita insieme alla compilazione di altre classi, la VM esaurisce lo spazio nello stack.La tua classe generata sta forse spingendo i limiti legali per i suoi contenuti.Vedi capitolo 4.10 Limitazioni della Java Virtual Machine In La specifica della macchina virtuale Java, seconda edizione.

Correzione 1:rifattorizzare la classe

Poiché la tua classe è in fase di generazione, questa potrebbe non essere un'opzione.Tuttavia, vale la pena esaminare le opzioni offerte dal tuo strumento di generazione di classi per vedere se può produrre qualcosa di meno problematico.

Correzione 2:aumentare la dimensione dello stack

Penso Kieron ha una soluzione quando menziona l'argomento -Xss. javac accetta una serie di argomenti non standard che variano a seconda della versione e del fornitore del compilatore.

Il mio compilatore:

$ javac -version
javac 1.6.0_05

Per elencare tutte le opzioni, utilizzerei questi comandi:

javac -help
javac -X
javac -J-X

IO pensare il limite dello stack per Javac è 512Kb per impostazione predefinita.Puoi aumentare la dimensione dello stack per questo compilatore a 10 Mb con questo comando:

javac -J-Xss10M Foo.java

Potresti essere in grado di passarlo in un file Ant con a compilerarg elemento nidificato nel tuo javac compito.

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

Altri suggerimenti

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

dal commento sopra non è corretto.Hai bisogno di uno spazio tra -J e -X, in questo modo:

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

per evitare il seguente errore:

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

...[javac] javac:contrassegno non valido:-J-xss1m [javac] utilizzo:javac

Prova ad aggiungere qualche variazione di questi attributi al file Formica javac compito linea:

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

Puoi anche provare fork="true", non sono sicuro che questo ti consenta di impostare valori per stack e heap (aka -Xm1024), ma potrebbe essere d'aiuto (se funzionerebbe dalla riga di comando, ma non in Ant).

[Modificare]:Aggiunto collegamento: il javac compito sembrerebbe suggerire che i parametri di cui sopra richiedano anche l'impostazione fork="true".

Ciò accade quando esegui il comando javac dalla riga di comando?Potresti provare il forchetta attributo.

È abbastanza strano, 100 lezioni non sono poi così tante.Cosa fa il compilatore quando lo stack va in overflow?È stata generata un'utile traccia dello stack?Cosa succede se corri javac direttamente dalla riga di comando invece che tramite Ant?

Una possibile soluzione alternativa è semplicemente aumentare la dimensione dello stack utilizzando il file -Xss argomento alla JVM;o alla JVM in esecuzione ant o impostando fork="true" e un <compilerarg> sul <javac> compito.In realtà, ora che ci penso, il problema scompare semplicemente inserendo il file fork="true"?

Ecco cosa ho trovato.Dopo aver pubblicato la mia domanda ho continuato e ho modificato l'attività di compilazione con gli attributi fork="true", memoryinitialsize="256m" E memorymaximumsize="1024m" (oggi ho scoperto che questo è stato suggerito da Kieron e jmanning2k, grazie per il tuo tempo).Ciò non ha comunque risolto il problema.

Ho deciso di iniziare a rimuovere le classi dall'albero dei sorgenti per vedere se si poteva individuare il problema.Risulta che avevamo una classe client del servizio Web per Asse 1.4 che è stato generato automaticamente da un file WSDL.Ora, questa classe è un mostro (come in Frankenstein), ha 167 membri del campo (tutti di tipo String), 167 coppie getter/setter (1 per ogni campo), un costruttore che riceve tutti i 167 campi come parametri, un metodo equals che confronta tutti i 167 campi in modo strano.Per ciascun campo il confronto avviene in questo modo:

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

Il risultato di questo confronto viene "andato" (&&) con il risultato del confronto del campo successivo e così via.La classe prosegue con un metodo hashCode che utilizza anche tutti i campi, alcuni metodi di serializzazione XML personalizzati e un metodo che restituisce un oggetto metadati specifico di Axis che descrive la classe e che utilizza anche tutti i membri del campo.

Questa classe non viene mai modificata, quindi ho semplicemente inserito una versione compilata nel classpath dell'applicazione e il progetto è stato compilato senza problemi.

Ora, so che la rimozione di questo singolo file sorgente ha risolto il problema.Tuttavia, non ho assolutamente idea del motivo per cui questa particolare classe abbia causato il problema.Sarà bello saperlo;cosa può causare o causare uno StackOverflowError durante la compilazione del codice Java?Penso che pubblicherò quella domanda.

Per chi fosse interessato:

  • Windows XP SP2
  • JDK 1.4.2_17 di SUN
  • Formica 1.7.0
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top