Pregunta

Estoy tratando de compilar más de 100 clases de Java de diferentes paquetes de un directorio limpio (sin compilaciones incrementales) utilizando las siguientes tareas de hormiga:

<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 nuevamente, el compilador realiza una compilación incremental y todo funciona bien.Esto no es deseable ya que estamos usando Control de crucero hacer una compilación diaria automática y esto está provocando errores de compilación falsos.

Como solución rápida y sencilla, he creado 2 tareas separadas, compilando partes del proyecto en cada una.Realmente no creo que esta solución se mantenga a medida que se agreguen más clases en el futuro, y no quiero agregar nuevas tareas de compilación cada vez que alcancemos el "límite de compilación".

¿Fue útil?

Solución

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

Es probable que evaluar la expresión larga en su archivo Java consuma mucha memoria y, debido a que esto se hace junto con la compilación de otras clases, la VM simplemente se queda sin espacio en la pila.Su clase generada quizás esté superando los límites legales de su contenido.Ver capítulo 4.10 Limitaciones de la máquina virtual Java en La especificación de la máquina virtual Java, segunda edición.

Solución 1:refactorizar la clase

Dado que su clase se está generando, es posible que esta no sea 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.

Solución 2:aumentar el tamaño de la pila

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

Mi compilador:

$ javac -version
javac 1.6.0_05

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

javac -help
javac -X
javac -J-X

I pensar El límite de pila para javac es 512 Kb de forma predeterminada.Puede aumentar el tamaño de la pila de este compilador a 10 Mb con este comando:

javac -J-Xss10M Foo.java

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

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

Otros consejos

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

desde el comentario arriba 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:bandera no válida:-J-XSS1M [JAVAC] Uso:javac

Intente agregar alguna variación de estos atributos al Hormiga javac tarea línea:

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

También puedes probar fork="true", no estoy seguro de si esto le permite establecer valores para la pila y el montón (también conocido como -Xm1024), pero puede ayudar (si funcionara desde la línea de comando, pero no en Ant).

[Editar]:Enlace agregado: el javac tarea página parece sugerir que los parámetros anteriores requieren que usted también establezca fork="true".

¿Sucede esto cuando ejecuta el comando javac desde la línea de comando?Quizás quieras probar el tenedor atributo.

Eso es bastante extraño, 100 clases realmente no son tantas.¿Qué hace el compilador cuando la pila se desborda?¿Se genera un seguimiento de pila útil?¿Qué pasa si corres? javac ¿Directamente en la línea de comando en lugar de hacerlo completamente?

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

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 descubrí que esto fue sugerido por Kieron y jmanning2k, gracias por su tiempo).De todos modos, esto no resolvió el problema.

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 Eje 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 método igual 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 se "junta" (&&) 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 usa todos los campos, algunos métodos de serialización XML personalizados y un método que devuelve un objeto de metadatos específico de Axis que describe la clase y que también usa 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 se compiló sin problemas.

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

Para los interesados:

  • Windows XP SP2
  • JDK de SUN 1.4.2_17
  • Hormiga 1.7.0
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top