Jenkins CI - Impossibile allocare memoria


9

Ho testato jenkins-ci con successo su un Ubuntu 10.4 (con vmware fusion) sul mio computer locale. Ora voglio installarlo e usarlo sul mio server virtuale su hosteurope. L'installazione di base non è stata un problema, ma ora ho problemi con il mio progetto di build.

Dopo aver estratto un aggiornamento mercuriale da un repository, viene invocata la formica e genera il seguente errore nel mio progetto di build:

"Buildfile: /var/lib/jenkins/workspace/concrete5-seed-clean/build.xml [proprietà] java.io.IOException: Impossibile eseguire il programma" / usr / bin / env ": java.io.IOException: errore = 12, Impossibile allocare memoria "

Esiste un problema noto con la dimensione dell'heap sui server virtuali su hosteurope ( http://faq.hosteurope.de/index.php?cpid=13918 ), quindi ho provato a impostare manualmente la dimensione dell'heap:

# 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 

Dopo aver impostato questo per ant, il comando "ant -diagnostics" viene eseguito e non causa un errore, ma l'errore si verifica ancora quando provo a creare il progetto.

Dettagli server: - http://www.hosteurope.de/produkt/Virtual-Server-Linux-L

  • Ubuntu 10.4 LTS
  • RAM: 1 GB / dinamico 2 GB

Le mie domande: - 1 GB è sufficiente per Jenkins o devo aggiornare il server? - Questo errore è causato da formica o jenkins?

Aggiornamento: ho funzionato con le opzioni di formica -Xmx128m -Xms128m, ma a volte l'errore si verifica di nuovo. (Questo mi fa impazzire, perché ormai non riesco a riprodurlo: /)

Aiuto molto apprezzato!

Saluti, Matthias


Ho risolto questo problema impostando i file di configurazione di Jenkins: JENKINS_JAVA_OPTIONS = "- Djava.awt.headless = true -Xms500m -Xmx1000m"
herbertD

Risposte:


10

Orien è corretto, è la chiamata di sistema fork () attivata da ProcessBuilder o Runtime.exec o altri mezzi della JVM che esegue un processo esterno (ad es. Un'altra JVM che esegue la formica, un comando git, ecc.).

Ci sono stati alcuni post sulle mailing list di Jenkins su questo: Impossibile eseguire il programma "git" ... errore = 12, Impossibile allocare memoria

C'è una bella descrizione del problema nell'elenco degli sviluppatori di SCons: fork () + exec () vs posix_spawn ()

Esiste un rapporto sui bug JVM di lunga data con soluzioni: utilizzare posix_spawn, non fork, su S10 per evitare l'esaurimento degli swap . Ma non sono sicuro che questo sia effettivamente arrivato a JDK7 come i commenti suggeriscono che fosse il piano.

In sintesi, su sistemi simili a Unix, quando un processo (ad es. JVM) deve avviare un altro processo (ad es. Git) viene effettuata una chiamata di sistema fork()che duplica efficacemente il processo corrente e tutta la sua memoria (Linux e altri ottimizzano questo con copia -on-write in modo che la memoria non sia effettivamente copiata fino a quando il bambino non tenta di scrivergli). Il processo duplicato quindi effettua un'altra chiamata di sistema, exec()per avviare l'altro processo (ad es. Git) a quel punto tutta la memoria copiata dal processo genitore può essere scartata dal sistema operativo. Se il processo padre utilizza grandi quantità di memoria (come tendono a fare i processi JVM), la chiamata a fork()potrebbe non riuscire se il sistema operativo determina che non ha memoria sufficiente + scambio per contenere due copie, anche se il processo figlio non sarà mai effettivamente usa quella memoria copiata.

Esistono diverse soluzioni:

  • Aggiungi più memoria fisica / RAM alla macchina.

  • Aggiungi più spazio di swap per ingannare il fork()funzionamento, anche se lo spazio di swap non è strettamente necessario per nulla. Questa è la soluzione che ho scelto perché è abbastanza facile aggiungere un file di scambio e non volevo vivere con il potenziale per i processi che venivano uccisi a causa di un sovraccarico.

  • Su Linux, abilita l' overcommit_memoryopzione del sistema vm ( / proc / sys / vm / overcommit_memory ). Con overcommit, la chiamata a fork()avrebbe sempre successo e poiché il processo figlio non utilizzerà effettivamente quella copia della memoria, tutto va bene. Naturalmente, è possibile che con l'overcommit, i tuoi processi tenteranno effettivamente di utilizzare più memoria di quella disponibile e verranno eliminati dal kernel. Se questo è appropriato dipende dagli altri usi della macchina. Le macchine mission-critical probabilmente non dovrebbero rischiare che il killer di memoria insufficiente funzioni in modo anomalo. Ma un server di sviluppo interno che può permettersi dei tempi di inattività sarebbe un buon posto per abilitare il sovraccarico.

  • Modificare la JVM in modo da non utilizzare fork()+ exec()ma da utilizzare posix_spawn()quando disponibile. Questa è la soluzione richiesta nella precedente segnalazione di bug JVM e menzionata nella mailing list di SCons. È inoltre implementato in java_posix_spawn .

    Sto cercando di scoprire se quella correzione è diventata JDK7. In caso contrario, mi chiedo se la gente di Jenkins sarebbe interessata a un lavoro come java_posix_spawn. Sembra che ci siano stati tentativi di integrare quello in Apache commons-exec .

    Programmieraffe, non ne sono sicuro al 100%, ma il tuo link suggerisce che la correzione è in JDK7 e JDK6 1.6.0_23 e successive. Per la cronaca, stavo eseguendo OpenJDK 1.6.0_18.

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


Grazie per la risposta dettagliata! Nel relativo post Alf Høgemark afferma che ora è stato corretto: ( stackoverflow.com/a/9127548/809939 ) Qualcuno può confermarlo? Proverò ad aggiornare anche la mia versione di Java.
Programmieraffe,

Domanda aggiuntiva: cosa proporresti? Overcommit-Memoria-Setting? Saluti, Mattia
Programmieraffe

1
L'aggiunta di un file di scambio è semplice e diretta. Per Ubuntu 12.04 (anche se dovrebbe applicarsi in gran parte a Linux in generale), questo articolo era semplicissimo: digitalocean.com/community/articles/…
davemyron,

1

Nota il messaggio di eccezione: Cannot run program "/usr/bin/env": java.io.IOException: error=12, Cannot allocate memory"il processo Java sta tentando di eseguire il fork di un nuovo processo per eseguire il comando /usr/bin/envma il sistema operativo ha esaurito le risorse di memoria per creare un nuovo processo. Questo non è lo stesso della memoria virtuale della VM Java, quindi nessuna quantità di armeggi con flag -Xmx lo risolverà. Dovrai monitorare le risorse di memoria durante l'esecuzione della build. Aumentare lo spazio di swap probabilmente risolverà il tuo problema.


È la Java Virtual machine (una delle pile o pile) che non ha più memoria, NON il sistema del computer host.
mdpc,

Scusa la brevità della mia risposta originale. L'ho aggiornato per descrivere perché non è la memoria JVM a corto di memoria.
orien,

0

È probabile che ANT_OPTS venga sovrascritto da Jenkins. Puoi anche impostare le opzioni direttamente nel tuo file di build in modo da poter controllare l'allocazione della memoria indipendentemente dall'ambiente (shell, Jenkins, ...). Nel tuo file di build (esempio:

<java fork="true" classname="..." >
    <jvmarg line="-Xms512M -Xmx512M" />
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.