¿Cómo rastrear un programa java?

25

Como administrador de sistemas, a veces me enfrento a situaciones en las que un programa se comporta de manera anormal, sin crear errores ni mensajes de error sin sentido.

En el pasado, antes de que llegara Java, había dos contramedidas:

  1. Si nada más ayuda - RTFM ;-)
  2. Si incluso 1. no ayuda, rastree las llamadas al sistema y vea qué está sucediendo

Normalmente lo uso strace -fpara esta tarea con Linux (otros sistemas operativos tienen herramientas de rastreo similares). Ahora, si bien esto generalmente funciona bien para cualquier programa antiguo, la traza se vuelve muy borrosa cuando se hace lo mismo en un proceso de Java . Hay tantas llamadas al sistema que aparentemente no están relacionadas con ninguna acción real, que es terrible buscar en ese basurero.

¿Hay mejores formas de hacerlo (si el código fuente no está disponible)?

Nils
fuente

Respuestas:

16

Como mencionó ckhan, jstackes excelente porque proporciona el seguimiento completo de la pila de todos los subprocesos activos en la JVM. Lo mismo se puede obtener en stderr de la JVM usando SIGQUIT.

Otra herramienta útil es la jmapque puede obtener un volcado de pila del proceso JVM utilizando el PID del proceso:

jmap -dump:file=/tmp/heap.hprof $PID

Este volcado de visualvmalmacenamiento dinámico se puede cargar en herramientas como (que ahora forma parte de la instalación estándar de Oracle java sdk, llamada jvisualvm). Además, VisualVM puede conectarse a la JVM en ejecución y mostrar información sobre la JVM, incluida la visualización de gráficos de uso interno de CPU, recuento de subprocesos y uso de almacenamiento dinámico, ideal para rastrear fugas.

Otra herramienta, jstatpuede recopilar estadísticas de recolección de basura para la JVM durante un período de tiempo muy similar a vmstat cuando se ejecuta con un argumento numérico (por ejemplo vmstat 3).

Finalmente, es posible usar un Agente Java para impulsar la instrumentación en todos los métodos de todos los objetos en el momento de la carga. La biblioteca javassistpuede ayudar a hacer esto muy fácil de hacer. Por lo tanto, es factible agregar su propio rastreo. La parte difícil con eso sería encontrar una manera de obtener resultados de rastreo solo cuando lo deseara y no todo el tiempo, lo que probablemente ralentizaría la JVM. Hay un programa llamado dtraceque funciona de esta manera. Lo intenté, pero no tuve mucho éxito. Tenga en cuenta que los agentes no pueden instrumentar todas las clases porque las necesarias para arrancar la JVM se cargan antes de que el agente pueda instrumentar, y luego es demasiado tarde para agregar instrumentación a esas clases.

Mi sugerencia : comience con VisualVM y vea si eso le dice lo que necesita saber, ya que puede mostrar los hilos actuales y las estadísticas importantes para la JVM.

ceniza
fuente
Por cierto, esta es una pregunta increíble; Espero que más personas agreguen respuestas con otras ideas. Cuando le pregunté a la gente que trabajaba con Java durante muchos años sobre el rastreo, me dieron miradas en blanco. Quizás simplemente no conocen la genialidad de strace.
ceniza
10

En el mismo sentido, al depurar programas que han salido mal en un sistema Linux, puede usar herramientas similares para depurar ejecutando JVM en su sistema.

Herramienta # 1 - jvmtop

De manera similar top, puede usar jvmtop para ver qué clases están dentro de las JVM en ejecución en su sistema. Una vez instalado, lo invocas así:

$ jvmtop.sh

Su salida tiene un estilo similar al de la herramienta top:

 JvmTop 0.8.0 alpha   amd64  8 cpus, Linux 2.6.32-27, load avg 0.12
 http://code.google.com/p/jvmtop

  PID MAIN-CLASS      HPCUR HPMAX NHCUR NHMAX    CPU     GC    VM USERNAME   #T DL
 3370 rapperSimpleApp  165m  455m  109m  176m  0.12%  0.00% S6U37 web        21
11272 ver.resin.Resin [ERROR: Could not attach to VM]
27338 WatchdogManager   11m   28m   23m  130m  0.00%  0.00% S6U37 web        31
19187 m.jvmtop.JvmTop   20m 3544m   13m  130m  0.93%  0.47% S6U37 web        20
16733 artup.Bootstrap  159m  455m  166m  304m  0.12%  0.00% S6U37 web        46

Herramienta # 2 - jvmmonitor

Otra alternativa es usar jvmmonitor . JVM Monitor es un generador de perfiles Java integrado con Eclipse para monitorear el uso de CPU, subprocesos y memoria de aplicaciones Java. Puede usarlo para buscar automáticamente JVM en ejecución en el host local o puede conectarse a JVM remotas utilizando un puerto @ host.

ss de jvmmonitor

Herramienta # 3 - visualvm

visualvm es probablemente "la herramienta" a la que recurrir cuando se depuran problemas con la JVM. Su conjunto de características es bastante profundo y puede obtener una mirada muy profunda a las entrañas.

Perfile el rendimiento de la aplicación o analice la asignación de memoria:

ss de visualvm # 2

Tomar y mostrar volcados de subprocesos:

ss de visualvm # 3

Referencias

slm
fuente
4

Considere jstack. No es una coincidencia para strace, más bien un pstackanálogo, pero al menos le dará una imagen de una instantánea a tiempo. Podría unirlos para obtener un rastro tosco si fuera necesario.

Consulte también las sugerencias en este artículo de SO: /programming/1025681/call-trace-in-java

ckhan
fuente
2

Si está utilizando RHEL OpenJDK (o similar, el punto es que no es JDK de Oracle), puede usar SystemTap para eso.

Algunas sondas se habilitan mediante el uso de las opciones de línea de comandos de Java -XX:+DTraceMethodProbes, -XX:+DTraceAllocProbes, -XX:+DTraceMonitorProbes. Tenga en cuenta que habilitar estas sondas afectará significativamente el rendimiento del programa.

Aquí hay un ejemplo de Script SystemTap:

#!/usr/bin/stap

probe hotspot.class_loaded {
    printf("%12s [???] %s\n", name, class);
}

probe hotspot.method_entry, 
      hotspot.method_return {
    printf("%12s [%3d] %s.%s\n", name, thread_id, class, method);
}

probe hotspot.thread_start, 
      hotspot.thread_stop {
    printf("%12s [%3d] %s\n", name, id, thread_name);
}

probe hotspot.monitor_contended_enter, 
      hotspot.monitor_contended_exit {
    printf("%12s [%3d] %s\n", name, thread_id, class);
}

También puede usar jstack()para obtener la pila Java del proceso, pero solo funcionará si inicia SystemTap antes de JVM.


Tenga en cuenta que SystemTap rastreará todos los métodos. Tampoco puede obtener argumentos del método. Otra opción es utilizar las capacidades propias de rastreo de JVM, que se llama JVMTI. Una de las implementaciones de JVMTI más famosas es BTrace .

myaut
fuente
0

Se recomienda probar Jackplay , que es una herramienta de rastreo JVM que le permite rastrear la entrada y salida de métodos sin cambio de código o redistribución.

alfredx
fuente
No puede adjuntarlo a una JVM en ejecución. Aparte de eso - herramienta interesante
Nils