Jenkins CI - Impossible d'allouer de la mémoire

9

J'ai testé jenkins-ci avec succès sur un ubuntu 10.4 (avec fusion vmware) sur mon ordinateur local. Maintenant, je veux l'installer et l'utiliser sur mon serveur virtuel chez hosteurope. L'installation de base n'a pas posé de problème, mais j'ai maintenant des problèmes avec mon projet de construction.

Après avoir extrait une mise à jour mercurielle d'un référentiel, ant est invoqué et génère l'erreur suivante dans mon projet de génération:

"Buildfile: /var/lib/jenkins/workspace/concrete5-seed-clean/build.xml [propriété] java.io.IOException: impossible d'exécuter le programme" / usr / bin / env ": java.io.IOException: error = 12, Impossible d'allouer de la mémoire "

Il y a un problème connu avec la taille du tas sur les serveurs virtuels sur hosteurope ( http://faq.hosteurope.de/index.php?cpid=13918 ), j'ai donc essayé de définir la taille du tas manuellement:

# 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 

Après avoir défini cela pour ant, la commande "ant -diagnostics" s'exécute et ne provoque pas d'erreur, mais l'erreur se produit toujours lorsque j'essaie de générer le projet.

Détails du serveur: - http://www.hosteurope.de/produkt/Virtual-Server-Linux-L

  • Ubuntu 10.4 LTS
  • RAM: 1 Go / dynamique 2 Go

Mes questions: - 1 Go suffit-il pour Jenkins ou dois-je mettre à niveau le serveur? - Cette erreur est-elle causée par une fourmi ou un jenkins?

Mise à jour: je l'ai exécuté avec les options ant -Xmx128m -Xms128m, mais parfois l'erreur se reproduit. (cela me fait peur, car je ne peux pas le reproduire maintenant: /)

Aide très appréciée!

À la vôtre, Matthias

Programmieraffe
la source
J'ai résolu cela en définissant les fichiers de configuration jenkins: JENKINS_JAVA_OPTIONS = "- Djava.awt.headless = true -Xms500m -Xmx1000m"
herbertD

Réponses:

10

Orien a raison, c'est l'appel système fork () déclenché par ProcessBuilder ou Runtime.exec ou tout autre moyen de la JVM exécutant un processus externe (par exemple une autre JVM exécutant ant, une commande git, etc.).

Il y a eu quelques messages sur les listes de diffusion Jenkins à ce sujet: Impossible d'exécuter le programme "git" ... erreur = 12, Impossible d'allouer de la mémoire

Il y a une belle description du problème sur la liste des développeurs SCons: fork () + exec () vs posix_spawn ()

Il existe un rapport de bogue JVM de longue date avec des solutions: utilisez posix_spawn, pas fork, sur S10 pour éviter l'épuisement du swap . Mais je ne suis pas sûr que cela soit réellement arrivé au JDK7, comme le suggèrent les commentaires, c'était le plan.

En résumé, sur les systèmes de type Unix, lorsqu'un processus (par exemple la JVM) doit lancer un autre processus (par exemple git), un appel système est effectué vers fork()lequel duplique efficacement le processus en cours et toute sa mémoire (Linux et d'autres l'optimisent avec copie -on-write pour que la mémoire ne soit pas réellement copiée jusqu'à ce que l'enfant essaie d'y écrire). Le processus en double effectue ensuite un autre appel système, exec()pour lancer l'autre processus (par exemple git), auquel cas toute la mémoire copiée du processus parent peut être supprimée par le système d'exploitation. Si le processus parent utilise de grandes quantités de mémoire (comme les processus JVM ont tendance à le faire), l'appel à fork()peut échouer si le système d'exploitation détermine qu'il n'a pas assez de mémoire + swap pour contenir deux copies, même si le processus enfant ne sera jamais réellement utiliser cette mémoire copiée.

Il existe plusieurs solutions:

  • Ajoutez plus de mémoire physique / RAM à la machine.

  • Ajoutez plus d'espace de swap pour le fork()faire fonctionner, même si l'espace de swap n'est strictement nécessaire à rien. C'est la solution que j'ai choisie, car il est assez facile d'ajouter un fichier d'échange, et je ne voulais pas vivre avec le risque que des processus soient tués en raison d'une surcharge.

  • Sous Linux, activez l' overcommit_memoryoption du système vm ( / proc / sys / vm / overcommit_memory ). Avec overcommit, l'appel à fork()réussirait toujours, et puisque le processus enfant ne va pas réellement utiliser cette copie de la mémoire, tout va bien. Bien sûr, il est possible qu'avec overcommit, vos processus tentent en fait d'utiliser plus de mémoire que ce qui est disponible et soient tués par le noyau. La pertinence de cette option dépend des autres utilisations de la machine. Les machines essentielles à la mission ne devraient probablement pas risquer que le tueur en panne de mémoire fonctionne de manière folle. Mais un serveur de développement interne qui peut se permettre un certain temps d'arrêt serait un bon endroit pour activer la surcharge.

  • Modifiez la machine virtuelle Java pour ne pas utiliser fork()+ exec()mais pour l'utiliser posix_spawn()lorsqu'elle est disponible. Il s'agit de la solution demandée dans le rapport de bogue JVM ci-dessus et mentionnée sur la liste de diffusion SCons. Il est également mis en œuvre dans java_posix_spawn .

    J'essaie de savoir si ce correctif est entré dans JDK7. Sinon, je me demande si les Jenkins seraient intéressés par une solution comme java_posix_spawn. Il semble y avoir eu des tentatives pour intégrer cela dans Apache commons-exec .

    Programmieraffe, je ne suis pas sûr à 100%, mais votre lien suggère que le correctif est dans JDK7 et JDK6 1.6.0_23 et versions ultérieures. Pour mémoire, j'utilisais OpenJDK 1.6.0_18.

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

Patrick
la source
Merci pour la réponse détaillée! Dans un article connexe, Alf Høgemark dit que cela est corrigé maintenant: ( stackoverflow.com/a/9127548/809939 ) Quelqu'un peut-il confirmer cela? J'essaierai également de mettre à jour ma version java.
Programmieraffe
Question supplémentaire: que proposeriez-vous? Overcommit-Memory-Setting? Cordialement, Matthias
Programmieraffe
1
L'ajout d'un fichier d'échange est simple et direct. Pour Ubuntu 12.04 (bien qu'il devrait s'appliquer en grande partie à Linux en général), cet article était simple: digitalocean.com/community/articles/…
davemyron
1

Notez le message d'exception: Cannot run program "/usr/bin/env": java.io.IOException: error=12, Cannot allocate memory"le processus Java tente de créer un nouveau processus pour exécuter la commande, /usr/bin/envmais le système d'exploitation n'a plus de ressources mémoire pour créer un nouveau processus. Ce n'est pas la même chose que la machine virtuelle Java manquant de mémoire, donc aucune quantité de manipulations avec les indicateurs -Xmx ne le corrigera. Vous devrez surveiller vos ressources mémoire lors de l'exécution de votre build. L'augmentation de l'espace d'échange résoudra probablement votre problème.

orien
la source
C'est la machine virtuelle Java (l'un des tas ou piles) qui est en mémoire et non le système informatique hôte.
mdpc
Excusez la brièveté de ma réponse originale. Je l'ai mis à jour pour décrire pourquoi ce n'est pas la JVM qui manque de mémoire.
orien
0

Il est probable que ANT_OPTS soit écrasé par Jenkins. Vous pouvez également définir les options directement dans votre fichier de build afin de pouvoir contrôler l'allocation de mémoire indépendamment de l'environnement (shell, Jenkins, ...). Dans votre fichier de build (exemple:

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