Las tareas de Ant <javac> arrojan StackOverflowException

votos
4

Estoy intentando compilar más de 100 clases de Java de diferentes paquetes desde un directorio limpio (sin compilaciones incrementales) usando las siguientes tareas de ant y

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

Sin embargo, la primera vez que ejecuto la tarea de compilación siempre obtengo una StackOverflowException. Si ejecuto la tarea de nuevo, el compilador realiza una compilación incremental y todo funciona bien. Esto es indeseable ya que estamos usando CruiseControl para hacer una compilación diaria automática y esto está causando fallas de compilación falsas.

Como una solución rápida y sucia, he creado 2 tareas separadas, compilando porciones del proyecto en cada una. Realmente no creo que esta solución se mantenga porque se agregan más clases en el futuro, y no quiero agregar nuevas tareas de compilación cada vez que lleguemos al límite de compilación.

Publicado el 19/08/2008 a las 19:53
por usuario
En otros idiomas...                            


6 respuestas

votos
1

¿Esto sucede cuando ejecuta el comando javac desde la línea de comando? Es posible que desee probar el atributo de horquilla .

Respondida el 19/08/2008 a las 20:04
fuente por usuario

votos
1

Intente agregar alguna variación de estos atributos a la línea de tarea Antjavac :

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

También puedes probar fork="true", no estoy seguro de si esto te permite establecer valores para stack y heap (aka -Xm1024), pero puede ser útil (si funciona desde la línea de comandos, pero no desde Ant).

[Editar]: Enlace agregado: la página de javactareas parece sugerir que los parámetros anteriores requieren que también lo haga fork="true".

Respondida el 19/08/2008 a las 20:05
fuente por usuario

votos
0

Eso es bastante extraño, 100 clases realmente no son tantas. ¿Qué está haciendo el compilador cuando la pila se desborda? ¿Se genera un rastro de pila útil? ¿Qué sucede si ejecuta javacdirectamente en la línea de comando en lugar de thorugh y hormiga?

Una posible solución es simplemente aumentar el tamaño de la pila usando el -Xssargumento para la JVM; ya sea a la JVM ejecutándose anto estableciendo fork="true"y a <compilerarg>en la <javac>tarea. En realidad, ahora que lo pienso, ¿el problema desaparece simplemente poniendo en el fork="true"?

Respondida el 19/08/2008 a las 20:21
fuente por usuario

votos
0

Esto es lo que encontré. Después de publicar mi pregunta, seguí y modifiqué la tarea de compilación con los atributos fork="true", memoryinitialsize="256m"y memorymaximumsize="1024m"(hoy encontré que esto fue sugerido por Kieron y jmanning2k, gracias por su tiempo). Esto no resolvió el problema, sin embargo.

Decidí comenzar a eliminar clases del árbol de fuentes para ver si podía identificar el problema. Resulta que teníamos una clase de cliente de servicio web para Axis 1.4 que se generó automáticamente a partir de un archivo WSDL. Ahora, esta clase es un monstruo (como en Frankenstein), tiene 167 miembros de campo (todos ellos de tipo String), 167 pares getter / setter (1 para cada campo), un constructor que recibe los 167 campos como parámetros, un es igual a un método que compara los 167 campos de una manera extraña. Para cada campo, la comparación es la siguiente:

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

El resultado de esta comparación es "anded" (&&) con el resultado de la comparación del siguiente campo, y así sucesivamente. La clase continúa con un método hashCode que también utiliza todos los campos, algunos métodos personalizados de serialización XML y un método que devuelve un objeto de metadatos específico del eje que describe la clase y que también utiliza todos los miembros del campo.

Esta clase nunca se modifica, así que simplemente puse una versión compilada en el classpath de la aplicación y el proyecto compilado sin problemas.

Ahora, sé que eliminar este único archivo fuente resolvió el problema. Sin embargo, no tengo absolutamente ninguna idea de por qué esta clase en particular causó el problema. Será bueno saberlo; ¿Qué puede causar o causar un StackOverflowError durante la compilación del código de Java? Creo que publicaré esa pregunta.

Para aquellos interesados:

  • Windows XP SP2
  • JDK de SUN 1.4.2_17
  • Ant 1.7.0
Respondida el 20/08/2008 a las 13:23
fuente por usuario

votos
4

Será bueno saberlo; ¿Qué puede causar o causar un StackOverflowError durante la compilación del código de Java?

Es probable que la evaluación de la expresión larga en el archivo java consuma mucha memoria y, como esto se realiza junto con la compilación de otras clases, la máquina virtual se queda sin espacio en la pila. Su clase generada tal vez está empujando los límites legales para sus contenidos. Consulte el capítulo 4.10 Limitaciones de la máquina virtual de Java en la especificación de la máquina virtual de Java, segunda edición .

Fix 1: refactorizar la clase

Dado que su clase se está generando, esta podría no ser una opción. Aún así, vale la pena mirar las opciones que ofrece su herramienta de generación de clases para ver si puede producir algo menos problemático.

Fix 2: aumenta el tamaño de la pila

Creo que Kieron tiene una solución cuando menciona el argumento -Xss. javac toma una serie de argumentos no estándar que variarán entre las versiones y los proveedores del compilador.

Mi compilador

$ javac -version
javac 1.6.0_05

Para enumerar todas las opciones para él, usaría estos comandos:

javac -help
javac -X
javac -J-X

Creo que el límite de la pila para javac es de 512 Kb por defecto. Puede aumentar el tamaño de la pila para este compilador a 10Mb con este comando:

javac -J-Xss10M Foo.java

Es posible que pueda pasar esto en un archivo Ant con un elemento compilerarg anidado en su tarea javac .

<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
    <compilerarg value="-J-Xss10M" />
</javac>
Respondida el 21/08/2008 a las 11:58
fuente por usuario

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

del comentario anterior es incorrecto. Necesitas un espacio entre -J y -X, así:

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

para evitar el siguiente error:

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

... [javac] javac: indicador no válido: -J-Xss1m [javac] Uso: javac

Respondida el 25/06/2009 a las 03:50
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more