Jenkins CI: no se puede asignar memoria

9

Probé jenkins-ci con éxito en un ubuntu 10.4 (con vmware fusion) en mi computadora local. Ahora quiero instalarlo y usarlo en mi servidor virtual en hosteurope. La instalación básica no fue un problema, pero ahora tengo problemas con mi proyecto de compilación.

Después de extraer una actualización mercurial de un repositorio, se invoca ant y arroja el siguiente error en mi proyecto de compilación:

"Buildfile: /var/lib/jenkins/workspace/concrete5-seed-clean/build.xml [propiedad] java.io.IOException: No se puede ejecutar el programa" / usr / bin / env ": java.io.IOException: error = 12, no se puede asignar memoria "

Existe un problema conocido con el tamaño de almacenamiento dinámico en los servidores virtuales en hosteurope ( http://faq.hosteurope.de/index.php?cpid=13918 ), así que intenté configurar el tamaño de almacenamiento dinámico 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 

Después de configurar esto para ant, el comando "ant -diagnostics" se ejecuta y no causa un error, pero el error aún ocurre cuando intento construir el proyecto.

Detalles del servidor: - http://www.hosteurope.de/produkt/Virtual-Server-Linux-L

  • Ubuntu 10.4 LTS
  • RAM: 1 GB / 2 GB dinámico

Mis preguntas: - ¿Es 1GB suficiente para Jenkins o tengo que actualizar el servidor? - ¿Es este error causado por hormiga o jenkins?

Actualización: lo ejecuté con las opciones ant -Xmx128m -Xms128m, pero a veces el error ocurre nuevamente. (Esto me asusta, porque no puedo reproducirlo por ahora: /)

Ayuda muy apreciada!

Saludos, Matías

Programmieraffe
fuente
Resolví esto estableciendo archivos de configuración de jenkins: JENKINS_JAVA_OPTIONS = "- Djava.awt.headless = true -Xms500m -Xmx1000m"
herbertD

Respuestas:

10

Orien es correcto, es la llamada al sistema fork () activada por ProcessBuilder o Runtime.exec u otros medios de la JVM que ejecuta un proceso externo (por ejemplo, otra JVM que ejecuta una hormiga, un comando git, etc.).

Ha habido algunas publicaciones en las listas de correo de Jenkins sobre esto: No se puede ejecutar el programa "git" ... error = 12, No se puede asignar memoria

Hay una buena descripción del problema en la lista de desarrolladores de SCons: fork () + exec () vs posix_spawn ()

Hay un informe de errores JVM de larga data con soluciones: use posix_spawn, no fork, en S10 para evitar el agotamiento del intercambio . Pero no estoy seguro de si esto realmente llegó a JDK7, ya que los comentarios sugieren que era el plan.

En resumen, en sistemas tipo Unix, cuando un proceso (por ejemplo, la JVM) necesita lanzar otro proceso (por ejemplo, git) se realiza una llamada al sistema fork()que duplica efectivamente el proceso actual y toda su memoria (Linux y otros optimizan esto con copia -on-write para que la memoria no se copie realmente hasta que el niño intente escribirle). Luego, el proceso duplicado realiza otra llamada al sistema exec()para iniciar el otro proceso (por ejemplo, git), en cuyo punto el sistema operativo puede descartar toda la memoria copiada del proceso principal. Si el proceso principal está utilizando grandes cantidades de memoria (como suelen hacer los procesos JVM), la llamada a fork()puede fallar si el sistema operativo determina que no tiene suficiente memoria + intercambio para contener dos copias, incluso si el proceso secundario nunca realmente usa esa memoria copiada.

Hay varias soluciones:

  • Agregue más memoria física / RAM a la máquina.

  • Agregue más espacio de intercambio para engañar fork()al trabajo, aunque el espacio de intercambio no sea estrictamente necesario para nada. Esta es la solución que elegí porque es bastante fácil agregar un archivo de intercambio, y no quería vivir con el potencial de que los procesos se maten debido a un exceso de compromiso.

  • En Linux, habilite la overcommit_memoryopción del sistema vm ( / proc / sys / vm / overcommit_memory ). Con el sobrecompromiso, la llamada a fork()siempre tendrá éxito, y dado que el proceso secundario en realidad no va a usar esa copia de la memoria, todo está bien. Por supuesto, es posible que con un exceso de compromiso, sus procesos realmente intenten usar más memoria de la que está disponible y el núcleo los eliminará. Si esto es apropiado depende de los otros usos de la máquina. Las máquinas de misión crítica probablemente no deberían arriesgarse a que el asesino sin memoria se vuelva loco. Pero un servidor de desarrollo interno que pueda permitirse un tiempo de inactividad sería un buen lugar para habilitar el exceso de compromiso.

  • Cambie la JVM para que no use fork()+ exec()sino para usar posix_spawn()cuando esté disponible. Esta es la solución solicitada en el informe de errores de JVM mencionado anteriormente y mencionado en la lista de correo SCons. También se implementa en java_posix_spawn .

    Estoy tratando de averiguar si esa solución llegó a JDK7. Si no, me pregunto si la gente de Jenkins estaría interesada en una solución como java_posix_spawn. Parece haber habido intentos de integrar eso en Apache commons-exec .

    Programmieraffe, no estoy 100% seguro, pero su enlace sugiere que la solución está en JDK7 y JDK6 1.6.0_23 y posteriores. Para el registro, estaba ejecutando OpenJDK 1.6.0_18.

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

Patricio
fuente
Gracias por la respuesta detallada! En la publicación relacionada, Alf Høgemark dice que esto se solucionó ahora: ( stackoverflow.com/a/9127548/809939 ) ¿Alguien puede confirmar esto? Intentaré actualizar mi versión de Java también.
Programmieraffe
Pregunta adicional: ¿Qué propondrías? ¿Configuración excesiva de memoria? Saludos, Matthias
Programmieraffe
1
Agregar un archivo de intercambio es fácil y directo. Para Ubuntu 12.04 (aunque debería aplicarse en gran medida a Linux en general), este artículo fue muy simple: digitalocean.com/community/articles/…
davemyron
1

Tenga en cuenta el mensaje de excepción: Cannot run program "/usr/bin/env": java.io.IOException: error=12, Cannot allocate memory"el proceso Java está tratando de bifurcar un nuevo proceso para ejecutar el comando, /usr/bin/envpero el sistema operativo se ha quedado sin recursos de memoria para crear un nuevo proceso. Esto no es lo mismo que la máquina virtual Java que se está quedando sin memoria, por lo que ninguna cantidad de retoques con banderas -Xmx lo solucionará. Tendrá que controlar sus recursos de memoria mientras ejecuta su compilación. Aumentar el espacio de intercambio probablemente solucionará su problema.

orien
fuente
Es la máquina virtual Java (uno de los montones o pilas) que no tiene memoria, NO el sistema de la computadora host.
mdpc
Disculpe la brevedad de mi respuesta original. Lo actualicé para describir por qué no se está quedando sin memoria la JVM.
orien
0

Es probable que Jenkins anule ANT_OPTS. También puede configurar las opciones directamente en su archivo de compilación para que pueda controlar la asignación de memoria independientemente del entorno (shell, Jenkins, ...). En su archivo de compilación (ejemplo:

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