Síntomas

La aplicación Java se ejecuta más lentamente y finalmente se queda sin memoria o se ve un error en los registros o en la salida de la consola OutOfMemoryError: Espacio de montículo de Java o OutOfMemoryError: Límite de sobrecarga de gc excedido.

Causa

Estos problemas pueden tener muchas causas.

Una posible causa es que la aplicación de Java, en nuestro caso, CRX/CQ se inicie desde la línea de comandos con la configuración predeterminada de memoria acumulada de Java. Esto significa que no se especificó el parámetro de jvm -Xmx. CRX o CQ necesitan al menos 256 MB del montículo asignado para funcionar. Si este es el problema, empezando por la línea de comandos, asegúrese de que la configuración de la memoria de pila esté establecida. Ejemplo:

java -Xmx512m -jar *.jar

Si este no es el caso, su aplicación podría estar reteniendo demasiados objetos sin liberarlos para la recopilación de residuos. Esto se llama fuga de memoria. Vaya aquí para más información. Vea la sección de abajo sobre cómo analizar problemas de memoria en aplicaciones Java.

Análisis, solución

Creación de volcado de montículos

Creación automática de un volcado de montículos

Para crear automáticamente un volcado de montículos cuando se está quedando sin memoria, puede añadir el parámetro jvm -XX:+HeapDumpOnOutOfMemoryError para generar un volcado de pilas automáticamente cuando la aplicación muestra el error OutOfMemoryError. Por ejemplo,

java -Xmx256m -XX:+HeapDumpOnOutOfMemoryError -jar *.jar

Esto crea un archivo de volcado en montículo (java_...hprof) en el directorio de trabajo del proceso cada vez que el proceso Java se queda sin memoria. El proceso puede continuar ejecutándose después de la creación de volcado de montículos. Por lo general, un archivo de volcado de montículos es suficiente para analizar el problema.

Nota: Si está usando el script crx-quickstart/server/start para iniciar su instancia de CRX, puede añadir -XX:+HeapDumpOnOutOfMemoryError a la variable CQ_JVM_OPTS (asegúrese de que la variable tampoco tenga ningún comentario). Por ejemplo:

CQ_JVM_OPTS='-XX:+HeapDumpOnOutOfMemoryError'

Después de añadir este parámetro y reiniciar la instancia CRX, verifique que la nueva opción jvm esté activada. Ejecute ps -ef | grep java desde la línea de comandos. Luego, compruebe si ve -XX:+HeapDumpOnOutOfMemoryError como un parámetro del proceso Java CRX.

Si necesita especificar un directorio diferente para generar el volcado de montículos debido a las restricciones de espacio en disco, puede agregar el parámetro -XX:HeapDumpPath=/path/to/generate/heapdump para indicarle a jvm dónde poner el archivo.

Consulte aquí una referencia de los parámetros jvm relacionados con la depuración.

Creación manual de un volcado de montículos

JVM Sun/Oracle

Para generar manualmente un volcado de montículo, ejecute este comando (jmap y jps se encuentran en la carpeta papelera del directorio principal de su JDK):

  1. busque el ID del proceso Java para el que está creando un volcado de montículos.
    • En Unix o Linux esto se puede hacer con ps -ef | grep java o jps -l
    • En Windows esto se puede hacer abriendo el administrador de tareas. Pulse Ctrl+Mayús+Esc y vaya a Ver => Seleccionar columnas => PID (identificador de proceso) o jps -l.
  2. Ejecute el comando jmap que se muestra a continuación, reemplace /path/to/generate/heapdumpfile.hprof con la ubicación en la que desea crear el archivo de volcado de montículos y reemplace 1234 con el Id del proceso que buscó en el paso anterior.
    jmap -dump:format=b,file=/path/to/generate/heapdumpfile.hprof 1234
    

IBM JVM

Para generar los volcados correctos en la señal de usuario, primero tendrá que cambiar la configuración predeterminada de JVM con respecto a los agentes de volcado. Existen varios tipos de volcado, pero generalmente necesita el volcado completo del sistema para realizar un análisis exhaustivo de la memoria. Añada los siguientes argumentos:

Xdump:heap:opts=PHD+CLASSIC:events=user -Xdump:system:events=user

Este evento de usuario ocurre cuando la JVM recibe la señal SIGQUIT (Linux, AIX®, z/OS® e i5/OS™) o SIGBREAK (Windows) del sistema operativo.

Para obtener más información, consulte aquí la documentación del vendedor.

Advertencia: Los archivos de volcado de montículos son grandes y pueden tener el mismo tamaño en disco que la configuración del parámetro max heap -Xmx jvm. Asegúrese de que tiene suficiente espacio en disco asignado al directorio donde se genera el archivo de volcado.

Análisis del volcado de montículos

Una buena herramienta para analizar los volcados de montículos es EclipseMAT (Eclipse Memory Analyzer): http://www.eclipse.org/mat/

Esta herramienta no puede analizar los volcados generados por IBM JVM. Para esos, existen varias posibilidades. IBM HeapAnalyzer hará bien para los volcados de montículos en formato PHD o clásico.

Para un análisis completo del volcado del sistema, utilice el espacio de trabajo del asistente de soporte de IBM con herramientas de diagnóstico y seguimiento de IBM para Java: Memory Analyzer versión 1.2 instalado en la parte superior.

Histograma en montículos

El histograma en montículos es una medida simple de la cantidad de objetos vivos y de memoria utilizados por clase Java. Desafortunadamente, dependiendo de la instalación de Java, es posible que las herramientas necesarias no estén disponibles o no siempre funcionen. Para crear un histograma en montículo, primero necesita el identificador de proceso del proceso Java. Para obtenerlo, ejecute ps o (si está disponible), ejecute:

jps -l

Esta herramienta Java obtiene los ID de proceso de todos los procesos Java en ejecución. Ejemplo:

327 3332 sun.tools.jps.Jps 3313 crx-quickstart-....jar

Ejecute el siguiente comando:

jmap -histo 3313

La lista está ordenada por memoria total requerida (superficial: excluyendo los objetos referenciados). Las primeras 20 líneas del resultado son las más interesantes. Ejemplo de resultado:

La versión JVM es 1.5.0_20-141 Iterando sobre un montículo. Esto puede tardar un poco.... Advertencia: Omisión de TLAB no válido para el subproceso t@62211 Advertencia: Omisión de TLAB no válido para el subproceso t@62467 .... Descripción de la clase de la cantidad de espacio ------------------------------------------------------- 10592904 12916 byte[]10285840 75255 * ConstMethodKlass 6283176 58388 char[] 6042304 14928 int[] 4995752 116201 * SymbolKlass 4220896 75255 * MethodKlass 4196512 6969 * ConstantPoolKlass 2928560 6969 * InstanceKlassKlass 2631008 6066 * ConstantPoolCacheKlass 2395872 149742 org.apache.jackrabbit.core.query.lucene.DocId$PlainDocId 1476008 7003 java.util.HashMap$Entry[] 1396128 58172 java.lang.String 1070232 44593 java.util.HashMap$Entry 753984 10036 short[] 735464 54 org.apache.jackrabbit.core.query.lucene.DocId[] 720192 7502 java.lang.Class 640704 13348 com.day.crx.persistence.tar.index.IndexEntry ...

Información adicional

Para ayudar a analizar el problema, también necesitamos conocer la siguiente información:

  • Versión CRX o CQ, incluyendo un listado de todas las correcciones instaladas.
  • Sistema operativo, proveedor de JVM y versión.

Referencias

[1] http://java.sun.com/javase/6/webnotes/trouble/TSG-VM/html/memleaks.html
[2] http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp#DebuggingOptions