Generar un Java thread dump con OpenJDK y Tomcat

Un «thread dump» de Java no es otra cosa que un volcado de todos los hilos que hay en ejecución en una JVM (Java Virtual Machine). En el caso de la JVM Tomcat, nos genera un listado de todos los threads y toda la información necesaria sobre cada uno de ellos para poder solucionar cualquier problema relacionado con la máquina virtual de Java y Tomcat.

Vamos a ver los pasos (muy sencillos) para generar el thread dump en OpenJDK. Recalco que es para OpenJDK porque hay métodos que funcionan con la JVM de Oracle pero no en OpenJDK.

Localizar el PID de la JVM de Tomcat

El Java thread dump se extrae del proceso de la JVM así que debemos conocer su PID. Podemos hacerlo con el comando ps o con el comando jps, que viene incluido en java JDK y muestra un listado de todos los procesos Java corriendo en la máquina y su PID (Process ID):

Método «ps»:

# ps -ef | grep jvm | grep -v grep
tomcat    1787     1  2 19:13 ?        00:00:07 /usr/lib/jvm/jre/bin/java
-Djavax.sql.DataSource.Factory=org.apache.commons.dbcp.BasicDataSourceFactory
-classpath :/usr/share/tomcat6/bin/bootstrap.jar:/usr/share/tomcat6/bin/tomcat-juli.jar
:/usr/share/java/commons-daemon.jar -Dcatalina.base=/usr/share/tomcat6 -Dcatalina.home=
/usr/share/tomcat6 -Djava.endorsed.dirs= -Djava.io.tmpdir=/var/cache/tomcat6/temp -Djava
.util.logging.config.file=/usr/share/tomcat6/conf/logging.properties -Djava.util.logging
.manager=org.apache.juli.ClassLoaderLogManager org.apache.catalina.startup.Bootstrap start

Método «jps»:

# jps -l
1787 org.apache.catalina.startup.Bootstrap
1835 sun.tools.jps.Jps

Si no tenéis instalada la JDK, podéis instalarla tanto por yum (RHEL, CentOS, Fedora…) como apt (Debian, Ubuntu). Hay que instalar el paquete de desarrollo (devel) Para la versión 1.7.9, por ejemplo:

# yum install java-1.7.0-openjdk-devel
# apt-get install openjdk-7-source

Generar el Thread Dump

Para generar el volcado utilizamos otro comando disponible en la JDK, «jstack«. Únicamente es necesario pasar a jstack como parámetro el PID del proceso sobre el que generar el dump. En este caso el proceso de la JVM es el 1787:

# jstack 1787
Attaching to process ID 1787, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 24.65-b04
Full thread dump OpenJDK ...

Como podéis observar el dump se genera en STDOUT así que es conveniente redirigirlo a un archivo:

# jstack 1787 > dump.txt

Las opciones de jstack son las siguientes, podemos forzar el dump aunque el proceso no responda, mostrar información ampliada sobre bloqueos, conectarnos a un servidor de debug remoto…

    jstack [-l] 
        (to connect to running process)
    jstack -F [-m] [-l] 
        (to connect to a hung process)
    jstack [-m] [-l]  
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack  does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

A partir de aquí queda lo más duro, interpretar el volcado para encontrar el origen del problema con el que nos estamos enfrentando. En el dump encontraréis información muy valiosa como el estado de cada uno de los thread (NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING), la información del thread, excepciones, etc.

Este método de debug y diagnostico de la JVM y Tomcat lo podemos combinar con otros que veremos en futuros artículos: JMX, jConsole, jstat