Pergunta

Estou tentando compilar mais de 100 aulas de Java de diferentes pacotes de um diretório limpo (sem compilos incrementais) usando as seguintes tarefas de formiga:

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

No entanto, na primeira vez que executo a tarefa de compilação, sempre recebo uma StackOverflowException.Se eu executar a tarefa novamente, o compilador fará uma compilação incremental e tudo funcionará bem.Isso é indesejável, pois estamos usando CruiseControl para fazer uma compilação diária automática e isso está causando falsas falhas de compilação.

Como uma solução rápida e simples, criei 2 tarefas separadas, compilando partes do projeto em cada uma.Eu realmente não acho que esta solução será válida à medida que mais classes forem adicionadas no futuro, e não quero adicionar novas tarefas de compilação toda vez que atingirmos o "limite de compilação".

Foi útil?

Solução

Será bom saber;O que pode causar ou causar um StackOverFlowerRor durante a compilação do código Java?

É provável que a avaliação da expressão longa no seu arquivo Java consuma muita memória e, como isso está sendo feito em conjunto com a compilação de outras classes, a VM simplesmente fica sem espaço na pilha.Sua classe gerada talvez esteja ultrapassando os limites legais de seu conteúdo.Veja o capítulo 4.10 Limitações da Máquina Virtual Java em A especificação da máquina virtual Java, segunda edição.

Correção 1:refatorar a classe

Como sua classe está sendo gerada, isso pode não ser uma opção.Ainda assim, vale a pena dar uma olhada nas opções que sua ferramenta de geração de classes oferece para ver se ela pode produzir algo menos problemático.

Correção 2:aumentar o tamanho da pilha

Eu penso Kieron tem uma solução quando menciona o argumento -Xss. javac aceita vários argumentos não padrão que variam entre versões e fornecedores de compiladores.

Meu compilador:

$ javac -version
javac 1.6.0_05

Para listar todas as opções, eu usaria estes comandos:

javac -help
javac -X
javac -J-X

EU pensar o limite de pilha para javac é 512 KB por padrão.Você pode aumentar o tamanho da pilha deste compilador para 10 MB com este comando:

javac -J-Xss10M Foo.java

Você pode passar isso em um arquivo Ant com um compilarg elemento aninhado em seu javac tarefa.

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

Outras dicas

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

de comente acima está incorreto.Você precisa de um espaço entre -J e -X, assim:

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

para evitar o seguinte erro:

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

...[javac]javac:sinalizador inválido:-J-xss1m [javac] Uso:javac

Tente adicionar alguma variação desses atributos ao Formiga javac tarefa linha:

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

Você também pode tentar fork="true", não tenho certeza se isso permite definir valores para pilha e heap (também conhecido como -Xm1024), mas pode ajudar (se funcionaria na linha de comando, mas não no Ant).

[Editar]:Link adicionado - o javac tarefa parece sugerir que os parâmetros acima exigem que você também defina fork="true".

Isso acontece quando você executa o comando javac na linha de comando?Você pode querer experimentar o garfo atributo.

Isso é muito estranho, 100 aulas não são tantas.O que o compilador está fazendo quando a pilha transborda?Existe um rastreamento de pilha útil gerado?O que acontece se você correr javac diretamente na linha de comando em vez de usar o ant?

Uma solução possível é simplesmente aumentar o tamanho da pilha usando o método -Xss argumento para a JVM;seja para a JVM em execução ant ou configurando fork="true" e um <compilerarg> no <javac> tarefa.Na verdade, agora que penso nisso, o problema desaparece apenas colocando o fork="true"?

Aqui está o que encontrei.Depois de postar minha pergunta, modifiquei a tarefa de compilação com os atributos fork="true", memoryinitialsize="256m" e memorymaximumsize="1024m" (descobri hoje que isso foi sugerido por Kieron e jmanning2k, obrigado pelo seu tempo).Mesmo assim, isso não resolveu o problema.

Decidi começar a remover classes da árvore de origem para ver se conseguia identificar o problema.Acontece que tínhamos uma classe de cliente Web Service para Eixo 1.4 que foi gerado automaticamente a partir de um arquivo WSDL.Agora, esta classe é um monstro (como em Frankenstein), tem 167 membros de campo (todos eles do tipo String), 167 pares getter/setter (1 para cada campo), um construtor que recebe todos os 167 campos como parâmetros, um método equals que compara todos os 167 campos de uma forma estranha.Para cada campo a comparação é assim:

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

O resultado desta comparação é "andado" (&&) com o resultado da comparação do próximo campo e assim por diante.A classe continua com um método hashCode que também usa todos os campos, alguns métodos de serialização XML personalizados e um método que retorna um objeto de metadados específico do Axis que descreve a classe e que também usa todos os membros do campo.

Esta classe nunca é modificada, então apenas coloquei uma versão compilada no classpath da aplicação e o projeto foi compilado sem problemas.

Agora, sei que a remoção desse arquivo de origem única resolveu o problema.No entanto, não tenho absolutamente nenhuma ideia de por que essa classe específica causou o problema.Será bom saber;o que pode causar ou causar um StackOverflowError durante a compilação do código Java?Acho que vou postar essa pergunta.

Para os interessados:

  • WindowsXP SP2
  • JDK 1.4.2_17 da SUN
  • Formiga 1.7.0
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top