tool - Inspección de hilos de Java en Linux con top
top linux tool (9)
Estoy inspeccionando un proceso de Java en Linux utilizando
top -H
Sin embargo, no puedo leer el nombre del hilo en la columna "COMANDO" (porque es demasiado largo). Si utilizo ''c'' para expandir el nombre completo del proceso, aún me queda mucho tiempo para que encaje.
¿Cómo puedo obtener el nombre completo del comando?
¿Aumenta la variable de entorno COLUMNS más información en la pantalla?
Con OpenJDK en Linux, los nombres JavaThread no se propagan a los hilos nativos , no se puede ver el nombre del hilo java mientras se inspeccionan los hilos nativos con cualquier herramienta.
Sin embargo, hay algo de trabajo en progreso:
- https://bugs.openjdk.java.net/browse/JDK-7102541
- http://mail.openjdk.java.net/pipermail/hotspot-dev/2012-July/006211.html
Personalmente, encuentro que la herramienta de desarrollo OpenJDK es lenta, así que solo aplico los parches.
Creé un comando tipo "top" específicamente para visualizar subprocesos Java ordenados por uso de CPU y publiqué el código fuente en: https://github.com/jasta/jprocps . La sintaxis de la línea de comandos no es tan rica como la de arriba, pero admite algunos de los mismos comandos:
jtop -n 1
Salida de muestra (mostrando hormiga e IntelliJ en ejecución):
PID TID USER %CPU %MEM THREAD 13480 13483 jasta 104 2.3 main 13480 13497 jasta 86.3 2.3 C2 CompilerThread1 13480 13496 jasta 83.0 2.3 C2 CompilerThread0 4866 4953 jasta 1.0 13.4 AWT-EventQueue-1 12.1.4#IC-129.713, eap:false 4866 14154 jasta 0.9 13.4 ApplicationImpl pooled thread 36 4866 5219 jasta 0.8 13.4 JobScheduler pool 5/8
A partir de esta salida, puedo extraer el seguimiento de pila del subproceso en jconsole o jstack de forma manual y averiguar qué está pasando.
Este script de shell combina el resultado de jstack y top para mostrar los hilos de Java por uso de CPU. Espera un argumento, el usuario de la cuenta que posee los procesos.
Nombre: jstack-top.sh
#!/bin/sh
#
# jstack-top - join jstack and top to show cpu usage, etc.
#
# Usage: jstack-top <user> | view -
#
USER=$1
TOPS="/tmp/jstack-top-1.log"
JSKS="/tmp/jstack-top-2.log"
PIDS="$(ps -u ${USER} --no-headers -o pid:1,cmd:1 | grep ''bin/java'' | grep -v ''grep'' | cut -d'' '' -f1)"
if [ -f ${JSKS} ]; then
rm ${JSKS}
fi
for PID in ${PIDS}; do
jstack -l ${PID} | grep "nid=" >>${JSKS}
done
top -u ${USER} -H -b -n 1 | grep "%CPU/|java" | sed -e ''s/[[:space:]]*$//'' > ${TOPS}
while IFS= read -r TOP; do
NID=$(echo "${TOP}" | sed -e ''s/^[[:space:]]*//'' | cut -d'' '' -f1)
if [ "${NID}" = "PID" ]; then
JSK=""
TOP="${TOP} JSTACK"
else
NID=$(printf ''nid=0x%x'' ${NID})
JSK=$(grep "${NID} " ${JSKS})
fi
echo "${TOP} ${JSK}"
done < "${TOPS}"
Esto podría ser un poco viejo, pero esto es lo que hice para fusionar un poco y apilar juntos. Usé dos scripts, pero estoy seguro de que todo podría hacerse en uno.
Primero, guardo el resultado de la parte superior con los pids para mis hilos java en un archivo y guardo el archivo jstack en otro archivo:
#!/bin/sh
top -H -b -n 1 | grep java > /tmp/top.log
jstack -l `ps fax | grep java | grep tomcat | sed "s/ */([0-9]*/) .*//1/g"` > /tmp/jstack.log
Luego uso una secuencia de comandos perl para llamar al script bash (llamado cpu-java.sh aquí) y unir los dos archivos (/tmp/top.log y /tmp/jstack.log):
#!/usr/bin/perl
system("sh cpu-java.sh");
open LOG, "/tmp/top.log" or die $!;
print "PID/tCPU/tMem/tJStack Info/n";
while ($l = <LOG>) {
$pid = $l;
$pid =~ s/root.*//g;
$pid =~ s/ *//g;
$hex_pid = sprintf("%#x", $pid);
@values = split(//s{2,}/, $l);
$pct = $values[4];
$mem = $values[5];
open JSTACK, "/tmp/jstack.log" or die $!;
while ($j = <JSTACK>){
if ($j =~ /.*nid=.*/){
if ($j =~ /.*$hex_pid.*/){
$j =~ s//n//;
$pid =~ s//n//;
print $pid . "/t" . $pct . "/t" . $mem . "/t" . $j . "/n";
}
}
}
close JSTACK;
}
close LOG;
La salida me ayuda a descubrir qué hilos están acaparando mi CPU:
PID CPU Mem JStack Info
22460 0 8.0 "main" prio=10 tid=0x083cb800 nid=0x57bc runnable [0xb6acc000]
22461 0 8.0 "GC task thread#0 (ParallelGC)" prio=10 tid=0x083d2c00 nid=0x57bd runnable
22462 0 8.0 "GC task thread#1 (ParallelGC)" prio=10 tid=0x083d4000 nid=0x57be runnable
22463 0 8.0 "GC task thread#2 (ParallelGC)" prio=10 tid=0x083d5800 nid=0x57bf runnable
22464 0 8.0 "GC task thread#3 (ParallelGC)" prio=10 tid=0x083d7000 nid=0x57c0 runnable
...
Luego, puedo volver a /tmp/jstack.log y echar un vistazo al seguimiento de la pila para el hilo problemático y tratar de averiguar qué está pasando desde allí. Por supuesto, esta solución depende de la plataforma, pero debería funcionar con la mayoría de los sabores de * nix y algunos ajustes aquí y allá.
Los hilos no tienen nombres en lo que se refiere al kernel; solo tienen números de identificación. La JVM asigna nombres a los hilos, pero eso son datos internos privados dentro del proceso, que el programa "superior" no puede acceder (y de todos modos no conoce).
Por lo que he descubierto, jstack está desactualizado a partir de JDK 8. Lo que utilicé para recuperar todos los nombres de subprocesos de Java es:
<JDK_HOME>/bin/jcmd <PID> Thread.print
Consulte la documentación de jcmd para más información.
Puede inspeccionar hilos de Java con la herramienta jstack
. Enumerará los nombres, stacktraces y otra información útil de todos los hilos que pertenecen al proceso especificado pid.
Editar : El parámetro nid en el volcado de subprocesos de jstack es la versión hexadecimal del LWP que se muestra arriba en la columna pid para subprocesos.
Una vieja pregunta, pero tenía el mismo problema con la top
.
Resulta que puedes desplazar la salida de la parte superior hacia la derecha simplemente usando las teclas cursoras :)
(pero desafortunadamente no se mostrará ningún nombre de hilo)