thread full java multithreading thread-dump

java - full - thread dump analyzer



Cómo analizar un volcado de hilo de Java? (3)

Estoy tratando de entender más sobre Java, especialmente sobre la administración de la memoria y los hilos. Por esta razón, recientemente he encontrado interés en buscar tiraderos de hilo.

Aquí hay algunas líneas tomadas de una aplicación web que utiliza VisualVM, una herramienta incorporada para Java:

"Finalizer" daemon prio=8 tid=0x02b3d000 nid=0x898 in Object.wait() [0x02d0f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) - locked <0x27ef0288> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159) Locked ownable synchronizers: - None "Reference Handler" daemon prio=10 tid=0x02b3b800 nid=0x494 in Object.wait() [0x02cbf000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x27ef0310> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0x27ef0310> (a java.lang.ref.Reference$Lock)

Primero tengo preguntas sobre algunos nombres de variables:

  • ¿Qué significa tid y nid?
  • ¿Cuál es la figura en paréntesis cuadrado después de Object.wait?

Luego, para la pila, trace él mismo:

  • ¿Qué significa esperar en <.....> (a java.lang ....) y cuál es el número en <..>
  • ¿Qué significa bloqueado <.....> (a java.lang ....) la misma pregunta, qué hay en <..>

Pensé que la palabra bloqueado estaba relacionada de alguna manera con una condición de espera, sin embargo, estaba equivocado. De hecho, me pregunto por qué el bloqueo se repite tres veces, pero el hilo está en estado ejecutable como se ve en el mismo volcado:

"Thread-0" prio=6 tid=0x02ee3800 nid=0xc1c runnable [0x03eaf000] java.lang.Thread.State: RUNNABLE at java.io.FileInputStream.readBytes(Native Method) at java.io.FileInputStream.read(FileInputStream.java:199) at java.io.BufferedInputStream.read1(BufferedInputStream.java:256) at java.io.BufferedInputStream.read(BufferedInputStream.java:317) - locked <0x23963378> (a java.io.BufferedInputStream) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158) - locked <0x23968450> (a java.io.InputStreamReader) at java.io.InputStreamReader.read(InputStreamReader.java:167) at java.io.BufferedReader.fill(BufferedReader.java:136) at java.io.BufferedReader.readLine(BufferedReader.java:299) - locked <0x23968450> (a java.io.InputStreamReader) at java.io.BufferedReader.readLine(BufferedReader.java:362) at org.codehaus.plexus.util.cli.StreamPumper.run(StreamPumper.java:145)

Luego, por último, este fue el peor de ellos:

"CompilerThread0" daemon prio=10 tid=0x02b81000 nid=0x698 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE

Este hilo está en estado ejecutable, pero está esperando a condición. ¿Qué condición y qué es 0x00000?

¿Por qué el seguimiento de la pila es tan corto sin evidencia de la clase de subprocesos?

Si pudiera responder a todas mis preguntas, estaría muy agradecido.

Gracias


Además de la excelente respuesta de @James Drinkard:

Tenga en cuenta que, dependiendo de la implementación subyacente, el java.lang.Thread.State de un hilo que está bloqueado en un método nativo puede informarse como RUNNABLE , donde se A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

Resulta que esta descripción también incluye el bloqueo en una llamada al sistema operativo, como una operación de sondeo o lectura, presumiblemente porque no hay garantía de que la JVM pueda saber cuándo una llamada de método nativo ha sido bloqueada en el nivel del sistema operativo.

Muchas discusiones sobre los volcados de hebras de JVM que he visto o bien ignoran esta posibilidad por completo, o simplemente las hojean sin considerar las implicaciones, una de las cuales es que las herramientas de monitoreo pueden informar confusamente que varios de estos hilos están ''ejecutándose'', y además que todos funcionan al 100%.


El TID es una ID de acceso y NID es: ID de hilo nativo. Esta ID depende en gran medida de la plataforma. Es el NID en los volcados de hilo jstack. En Windows, es simplemente la identificación de subprocesos de nivel de sistema operativo dentro de un proceso. En Linux y Solaris, es el PID del hilo (que a su vez es un proceso liviano). En Mac OS X, se dice que es el valor pthread_t nativo.

Vaya a este enlace: ID del hilo del nivel de Java : para obtener una definición y una explicación más detallada de estos dos términos.

En el sitio de IBM encontré este enlace: Cómo interpretar un volcado de hilo . que cubre esto en mayor detalle:

Explica qué significa esperar: un bloqueo impide que más de una entidad acceda a un recurso compartido. Cada objeto en Java ™ tiene un bloqueo asociado (ganado mediante el uso de un bloque o método sincronizado). En el caso de la JVM, los subprocesos compiten por varios recursos en la JVM y bloquean los objetos de Java.

Luego describe el monitor como un tipo especial de mecanismo de bloqueo que se utiliza en la JVM para permitir una sincronización flexible entre los hilos. Para el propósito de esta sección, lea los términos "monitorear" y "bloquear" de manera intercambiable.

Luego va más allá:

Para evitar tener un monitor en cada objeto, la JVM usualmente usa un indicador en una clase o bloque de método para indicar que el elemento está bloqueado. La mayoría de las veces, una porción de código transitará alguna sección bloqueada sin contención. Por lo tanto, la bandera de guardián es suficiente para proteger esta pieza de código. Esto se llama monitor plano. Sin embargo, si otro subproceso desea acceder a algún código que está bloqueado, se ha producido una disputa genuina. La JVM ahora debe crear (o inflar) el objeto del monitor para mantener el segundo hilo y disponer un mecanismo de señalización para coordinar el acceso a la sección del código. Este monitor ahora se llama monitor inflado.

Aquí hay una explicación más profunda de lo que está viendo en las líneas del volcado de subprocesos. Un subproceso de Java se implementa mediante un subproceso nativo del sistema operativo. Cada hilo está representado por una línea en negrita, como:

"Thread-1" (TID: 0x9017A0, sys_thread_t: 0x23EAC8, estado: R, ID nativo: 0x6E4) prio = 5

* Los siguientes 6 elementos explican esto porque los he emparejado del ejemplo, valores entre los corchetes []:

  1. nombre [ TID: 0x9017A0 ],
  2. identificador [ sys_thread_t ],
  3. Dirección de estructura de datos JVM [ 0x23EAC8 ],
  4. estado actual [ estado: R ],
  5. identificador de hilo nativo [ 0x6E4 ],
  6. y prioridad [ prio = 5 ].

El "esperar" parece ser un hilo de daemon asociado con el propio jvm y no el hilo de la aplicación en sí. Cuando obtienes un "en Object.wait ()", eso significa que el hilo del daemon, "finalizador" aquí, está esperando una notificación sobre un bloqueo en un objeto, en este caso te muestra qué notificación está esperando: "- esperando <0x27ef0288> (a java.lang.ref.ReferenceQueue $ Lock) "

La definición de la ReferenceQueue es: Colas de referencia, a las que el recolector de elementos no utilizados añade los objetos de referencia registrados después de detectar los cambios de accesibilidad apropiados.

El subproceso finalizador se ejecuta para que la recolección de elementos no utilizados funcione para limpiar los recursos asociados con un objeto. Si lo veo corectly, el finalizador no puede obtener el bloqueo de este objeto: java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118) porque el objeto java ejecuta un método, por lo que el hilo del finalizador es bloqueado hasta que ese objeto haya terminado con su tarea actual.

Además, el finalizador no solo busca reclamar memoria, sino que está más involucrado que eso para limpiar los recursos. Necesito estudiar más sobre él, pero si tiene archivos abiertos, tomas de corriente, etc ... relacionadas con un método de objetos, entonces el finalizador también va a trabajar para liberar esos elementos.

¿Cuál es la cifra en paréntesis cuadrado después de Object.wait en el volcado de hilo?

Es un puntero en la memoria del hilo. Aquí hay una descripción más detallada:

C.4.1 Información sobre el hilo

La primera parte de la sección del hilo muestra el hilo que provocó el error fatal, de la siguiente manera:

Current thread (0x0805ac88): JavaThread "main" [_thread_in_native, id=21139] | | | | +-- ID | | | +------------- state | | +-------------------------- name | +------------------------------------ type +-------------------------------------------------- pointer

El puntero de subproceso es el puntero a la estructura de subproceso interno de Java VM. En general, no tiene ningún interés a menos que esté depurando una máquina virtual Java en vivo o un archivo central.

Esta última descripción proviene de: Guía de solución de problemas para Java SE 6 con HotSpot VM

Aquí hay algunos enlaces más sobre volcados de subprocesos: