Jenkins CI - Não é possível alocar memória

9

Testei o jenkins-ci com sucesso em um ubuntu 10.4 (com fusão de vmware) no meu computador local. Agora eu quero instalar e usá-lo no meu servidor virtual na hosteurope. A instalação básica não foi um problema, mas agora tenho problemas com meu projeto de construção.

Depois de extrair uma atualização mercurial de um repositório, o ant é invocado e lança o seguinte erro no meu projeto de construção:

"Buildfile: /var/lib/jenkins/workspace/concrete5-seed-clean/build.xml [propriedade] java.io.IOException: Não é possível executar o programa" / usr / bin / env ": java.io.IOException: error = 12, não é possível alocar memória "

Há um problema conhecido com o tamanho da pilha nos servidores virtuais em hosteurope ( http://faq.hosteurope.de/index.php?cpid=13918 ), então tentei definir o tamanho da pilha manualmente:

# for ant
export ANT_OPTS="-Xms512m -Xmx512m"

# jenkins
# edited /etc/default/jenkins, added line 
JAVA_ARGS="-Xms512m -Xmx512m"
# restarted jenkins via /etc/init.d/jenkins restart 

Depois de definir isso para ant, o comando "ant -diagnostics" é executado e não causa um erro, mas o erro ainda ocorre quando tento criar o projeto.

Detalhes do servidor: - http://www.hosteurope.de/produkt/Virtual-Server-Linux-L

  • Ubuntu 10.4 LTS
  • RAM: 1 GB / 2 GB Dinâmicos

Minhas perguntas: - 1 GB é suficiente para Jenkins ou preciso atualizar o servidor? - Esse erro é causado por formigas ou jenkins?

Atualização: eu consegui rodar com as opções de formiga -Xmx128m -Xms128m, mas às vezes o erro ocorre novamente. (isso me assusta, porque eu não posso reproduzi-lo agora: /)

Ajuda muito apreciada!

Saúde, Matthias

Programmieraffe
fonte
Resolvi isso configurando os arquivos de configuração de jenkins: JENKINS_JAVA_OPTIONS = "- Djava.awt.headless = true -Xms500m -Xmx1000m"
herbertD

Respostas:

10

Orien está correto, é a chamada do sistema fork () acionada pelo ProcessBuilder ou Runtime.exec ou outros meios da JVM executando um processo externo (por exemplo, outra JVM executando ant, um comando git, etc.).

Houve algumas postagens nas listas de discussão Jenkins sobre isso: Não é possível executar o programa "git" ... erro = 12, Não é possível alocar memória

Há uma boa descrição do problema na lista de desenvolvedores do SCons: fork () + exec () vs posix_spawn ()

Há um longo relatório de bug da JVM com soluções: Use posix_spawn, não fork, no S10 para evitar a exaustão da troca . Mas não tenho certeza se isso realmente chegou ao JDK7, pois os comentários sugerem que era o plano.

Em resumo, em sistemas do tipo Unix, quando um processo (por exemplo, a JVM) precisa iniciar outro processo (por exemplo, git), é feita uma chamada para o sistema fork()que duplica efetivamente o processo atual e toda a sua memória (Linux e outros otimizam isso com cópia) -on-write para que a memória não seja realmente copiada até que a criança tente gravá-la). O processo duplicado faz outra chamada do sistema, exec()para iniciar o outro processo (por exemplo, git), no ponto em que toda a memória copiada do processo pai pode ser descartada pelo sistema operacional. Se o processo pai estiver usando grandes quantidades de memória (como costumam fazer os processos da JVM), a chamada fork()poderá falhar se o sistema operacional determinar que não há memória suficiente + troca para armazenar duas cópias, mesmo se o processo filho nunca realmente use essa memória copiada.

Existem várias soluções:

  • Adicione mais memória física / RAM à máquina.

  • Adicione mais espaço de troca para que o fork()trabalho funcione, mesmo que o espaço de troca não seja estritamente necessário para nada. Esta é a solução que eu escolhi porque é bastante fácil adicionar um arquivo de troca e não queria viver com o potencial de processos serem eliminados devido à confirmação excessiva.

  • No Linux, ative a overcommit_memoryopção do sistema vm ( / proc / sys / vm / overcommit_memory ). Com a confirmação excessiva, a chamada para fork()sempre seria bem-sucedida e, como o processo filho não vai realmente usar essa cópia da memória, tudo está bem. Obviamente, é possível que, com a supercomprometimento, seus processos realmente tentem usar mais memória do que a disponível e sejam mortos pelo kernel. Se isso é apropriado depende dos outros usos da máquina. Máquinas de missão crítica provavelmente não devem arriscar que o assassino de falta de memória fique louco. Mas um servidor de desenvolvimento interno que possa permitir algum tempo de inatividade seria um bom local para permitir a supercomprometimento.

  • Altere a JVM para não usar fork()+, exec()mas para usar posix_spawn()quando disponível. Esta é a solução solicitada no relatório de bug da JVM acima e mencionada na lista de discussão SCons. Também é implementado em java_posix_spawn .

    Estou tentando descobrir se essa correção chegou ao JDK7. Caso contrário, pergunto-me se o pessoal da Jenkins estaria interessado em uma solução alternativa, como java_posix_spawn. Parece ter havido tentativas de integrar isso ao Apache commons-exec .

    Programmieraffe, não tenho 100% de certeza, mas seu link sugere que a correção está no JDK7 e JDK6 1.6.0_23 e posterior. Para o registro, eu estava executando o OpenJDK 1.6.0_18.

Consulte /programming/1124771/how-to-solve-java-io-ioexception-error-12-cannot-allocate-memory-calling-run

Patrick
fonte
Obrigado pela resposta detalhada! No post relacionado, Alf Høgemark diz que isso está corrigido agora: ( stackoverflow.com/a/9127548/809939 ) Alguém pode confirmar isso? Vou tentar atualizar minha versão java também.
Programmieraffe
Pergunta adicional: O que você proporia? Overcommit-Memory-Setting? Atenciosamente, Matthias
Programmieraffe
1
Adicionar um arquivo de troca é fácil e direto. Para o Ubuntu 12.04 (embora deva se aplicar amplamente ao Linux em geral), este artigo era simples: digitalocean.com/community/articles/…
davemyron
1

Observe a mensagem de exceção: Cannot run program "/usr/bin/env": java.io.IOException: error=12, Cannot allocate memory"O processo Java está tentando bifurcar um novo processo para executar o comando, /usr/bin/envmas o sistema operacional ficou sem recursos de memória para criar um novo processo. Isso não é o mesmo que a Java VM ficando sem memória, portanto, nenhuma quantidade de mexer nos sinalizadores -Xmx o corrigirá. Você precisará monitorar seus recursos de memória enquanto executa sua compilação. Aumentar o espaço de troca provavelmente resolverá seu problema.

orien
fonte
É a máquina Java Virtual (uma das pilhas ou pilhas) que está sem memória e NÃO o sistema do computador host.
Mdpc
Desculpe a brevidade da minha resposta original. Eu o atualizei para descrever por que a JVM não está ficando sem memória.
Orien
0

É provável que ANT_OPTS sejam substituídos por Jenkins. Você também pode definir as opções diretamente no seu arquivo de construção, para poder controlar a alocação de memória independentemente do ambiente (shell, Jenkins, ...). No seu arquivo de construção (exemplo:

<java fork="true" classname="..." >
    <jvmarg line="-Xms512M -Xmx512M" />
Matteo
fonte