Serie de aprendizaje de comandos de Java (dos) -Jstack

Serie de aprendizaje de comandos de Java (dos) -Jstack

Incluido en el tema
#
7 Comandos de Linux

jstack es una herramienta de seguimiento de pila que viene con la máquina virtual Java.

Caracteristicas


jstack se utiliza para generar una instantánea del hilo de la máquina virtual Java en el momento actual. La instantánea de subprocesos es una colección de pilas de métodos que ejecuta cada subproceso en la máquina virtual Java actual. El objetivo principal de generar instantáneas de subprocesos es localizar la causa de pausas largas en subprocesos, como interbloqueos entre subprocesos, bucles sin fin y períodos prolongados causados ​​por solicitudes de recursos externos. Es hora de esperar y esperar. Cuando un hilo se detiene, puede ver la pila de llamadas de cada hilo a través de jstack, y puede saber qué está haciendo el hilo que no responde en segundo plano o qué recursos está esperando. Si el programa java falla para generar un archivo central, la herramienta jstack se puede usar para obtener la pila de Java y la información de la pila nativa del archivo principal, para que pueda saber fácilmente cómo se bloqueó el programa Java y dónde ocurrió el problema. Además, la herramienta jstack también se puede adjuntar al programa Java en ejecución, y puede ver la pila Java y la información de la pila nativa del programa Java en ejecución en ese momento.Si el programa Java en ejecución muestra un estado bloqueado, jstack es muy útil.

El comando So, jstack se usa principalmente para ver la pila de llamadas del subproceso de Java y se puede usar para analizar problemas de subprocesos (como interbloqueo).

Estado del hilo

Si desea analizar la situación de los subprocesos a través del comando jstack, primero debe saber qué estado tiene el subproceso. Los siguientes estados son los varios estados del subproceso que podemos ver cuando usamos el comando jstack para ver la información de la pila de subprocesos:

NUEVO, no activado. No aparecerá en Dump.

RUNNABLE, ejecutado en la máquina virtual.

BLOQUEADO, bloqueado y esperando que el monitor se bloquee.

WATING, esperando indefinidamente a que otro hilo realice una operación específica.

TIMED_WATING, espera por tiempo limitado para una operación específica de otro hilo.

TERMINADO, ha sido retirado.

Monitor

En un programa JAVA multiproceso, para lograr la sincronización entre subprocesos, es necesario hablar de Monitor. Monitor es el método principal utilizado para lograr la exclusión mutua y la cooperación entre subprocesos en Java. Puede verse como un bloqueo de un objeto o una clase. Cada objeto tiene, y solo un monitor. La siguiente figura describe la relación entre el hilo y el Monitor, y el diagrama de transición de estado del hilo:
Serie de aprendizaje de comandos de Java (dos) -Jstack

Entrt Set: Indica que el hilo adquiere el bloqueo del objeto a través de la solicitud sincronizada. Si el objeto no está bloqueado, ingrese el propietario; de lo contrario, espere en la zona de entrada. Una vez que el bloqueo del objeto es liberado por otros hilos, inmediatamente participa en la competencia.

Propietario (el propietario): indica que un subproceso compitió con éxito por el bloqueo de objeto.

Área de espera (Wait Set): Indica que el hilo libera el bloqueo del objeto a través del método de espera del objeto, y espera en el área de espera para ser despertado.

Se puede ver en la figura que un Monitor solo puede ser propiedad de un subproceso en un momento determinado. Este subproceso es "Subproceso activo", y los otros subprocesos son "Subproceso en espera", que están en dos colas "Conjunto de entrada" y "Conjunto de entrada" y "Subproceso en espera" respectivamente. Espere en "Wait Set". El estado del subproceso en espera en el "Conjunto de entrada" es "Esperando la entrada del monitor", y el estado del subproceso en espera en el "Conjunto de espera" es "en Object.wait ()". Primero mire los hilos en el "Conjunto de entrada". Llamamos al segmento de código protegido por sincronizado la sección crítica. Cuando un hilo solicita ingresar a la sección crítica, ingresa a la cola "Conjunto de entrada". El código correspondiente es como:


synchronized(obj) {
.........

}

Decoración de llamadas

Indica que el subproceso realiza operaciones importantes adicionales cuando se llama al método. Información importante para el análisis de volcado de subprocesos. Decora la llamada al método anterior.

<dirección> bloqueado Objetivo: solicitar con éxito el bloqueo de objetos utilizando sincronizado, el propietario del monitor.

esperando para bloquear <dirección> Objetivo: Utilizar sincronizado para solicitar el bloqueo de objetos sin éxito, esperar en el área de entrada.

esperando en <dirección> Objetivo: después de solicitar con éxito un bloqueo de objeto utilizando sincronizado, libere el bloqueo y espere en el área de espera.

estacionamiento para esperar <dirección> objetivo

bloqueado

at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at oracle.jdbc.driver.PhysicalConnection.prepareStatement
- locked <0x00002aab63bf7f58> (a oracle.jdbc.driver.T4CConnection)
at com.jiuqi.dna.core.internal.db.datasource.PooledConnection.prepareStatement

A través de la palabra clave sincronizada, obtuvo con éxito el bloqueo del objeto, se convirtió en el propietario del monitor y se operó en el área crítica. Los bloqueos de objetos son reentrantes.

esperando para bloquear

at com.jiuqi.dna.core.impl.CacheHolder.isVisibleIn(CacheHolder.java:165)
- waiting to lock <0x0000000097ba9aa8> (a CacheHolder)
at com.jiuqi.dna.core.impl.CacheGroup$Index.findHolder
at com.jiuqi.dna.core.impl.ContextImpl.find
at com.jiuqi.dna.bap.basedata.common.util.BaseDataCenter.findInfo

A través de la palabra clave sincronizada, no se adquiere el bloqueo del objeto y el hilo espera en el área de entrada del monitor. Aparece en la parte superior de la pila de llamadas y el estado del hilo es Bloqueado.

Esperando que

at java.lang.Object.wait(Native Method)
- waiting on <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo
- locked <0x00000000da2defb0> (a WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run

A través de la palabra clave sincronizada, luego de obtener exitosamente el bloqueo del objeto, llame al método de espera y entre al área de espera del objeto a esperar. En la parte superior de la pila de llamadas, el estado del hilo es WAITING o TIMED_WATING.

estacionamiento para esperar

park es una primitiva básica de bloqueo de subprocesos y no bloquea el objeto a través del monitor. El nuevo mecanismo que aparece con el paquete concurrente es diferente del sistema no sincronizado.

Acción del hilo

El motivo del estado del hilo

ejecutable: el estado es generalmente RUNNABLE.

en Object.wait (): Esperando en el área de espera, el estado es WAITING o TIMED_WAITING.

esperando la entrada del monitor: esperando la entrada a la zona, el estado está BLOQUEADO.

esperando con condición: esperando en la sala de espera, estacionado.

durmiendo: El hilo durmiente ha llamado Thread.sleep ().

Esperar en condición Este estado aparece cuando el hilo está esperando la ocurrencia de una determinada condición. La razón específica se puede analizar en combinación con stacktrace. La situación más común es que el hilo esté en estado de suspensión, esperando ser despertado. Una situación común es esperar la E / S de red: antes de que java presentara nio, para cada conexión de red, había un hilo correspondiente para manejar las operaciones de lectura y escritura de la red. Incluso si no hay datos que se puedan leer y escribir, el hilo sigue bloqueado en las operaciones de lectura y escritura. Por otro lado, esto puede causar un desperdicio de recursos y también ejercer presión sobre la programación de subprocesos del sistema operativo. Se adoptó un nuevo mecanismo en NewIO y se mejoraron el rendimiento y la escalabilidad del programa de servidor escrito. Esperando que la red lea y escriba, esto puede ser una señal de un cuello de botella en la red. El hilo no se puede ejecutar debido a la congestión de la red. Una situación es que la red está muy ocupada, casi todo el ancho de banda se consume y todavía hay una gran cantidad de datos esperando a que la red lea y escriba; la otra situación también puede ser que la red esté inactiva, pero debido a problemas de enrutamiento, los paquetes no pueden llegar normalmente. Por lo tanto, es necesario combinar algunas herramientas de observación del rendimiento del sistema para un análisis integral, como las estadísticas de netstat del número de paquetes enviados por unidad de tiempo, si obviamente excede el límite del ancho de banda de la red; observe la utilización de la CPU, si el tiempo de la CPU en el estado del sistema, en relación con La proporción de tiempo de CPU en el modo de usuario es relativamente alta; si el programa se está ejecutando en la plataforma Solaris 10, puede usar la herramienta dtrace para ver la situación de las llamadas al sistema, si observa el número de llamadas al sistema de lectura / escritura o si el tiempo de ejecución está muy adelantado; todos apuntan a la red Cuellos de botella en la red causados ​​por limitaciones de ancho de banda. (De http://www.blogjava.net/jzone/articles/303979.html)

Análisis de Thread Dump


en principio

Combina el razonamiento de lectura de código. Requiere derivación mutua y verificación de volcado de hilo y código fuente.

La causa raíz del error a menudo no se refleja directamente en la pila de llamadas, por lo que debe prestar especial atención a todas las llamadas antes de la llamada actual del hilo.

Punto de partida

Esperando en la zona

"d&a-3588" daemon waiting for monitor entry [0x000000006e5d5000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.dna.bap.authority.service.UserService$LoginHandler.handle()
- waiting to lock <0x0000000602f38e90> (a java.lang.Object)
at com.jiuqi.dna.bap.authority.service.UserService$LoginHandler.handle()

El estado del subproceso BLOQUEADO, la acción del subproceso espera en la entrada del monitor, la modificación de la llamada en espera para bloquearse siempre aparecen juntos. Indica que ya hay una llamada en conflicto a nivel de código. Debe haber un código problemático y su ocurrencia debe minimizarse.

Bloqueo de bloque de sincronización

Un hilo bloquea un objeto y una gran cantidad de otros hilos esperan en el objeto.


"blocker" runnable
java.lang.Thread.State: RUNNABLE
at com.jiuqi.hcl.javadump.Blocker$1.run(Blocker.java:23)
- locked <0x00000000eb8eff68> (a java.lang.Object)
"blockee-11" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)
"blockee-86" waiting for monitor entry
java.lang.Thread.State: BLOCKED (on object monitor)
at com.jiuqi.hcl.javadump.Blocker$2.run(Blocker.java:41)
- waiting to lock <0x00000000eb8eff68> (a java.lang.Object)

Las operaciones IO IO en ejecución continua se pueden bloquear en el estado RUNNABLE. Por ejemplo: bloqueo de la base de datos, lectura y escritura de la red. Preste especial atención al análisis del estado real del hilo IO. En términos generales, las llamadas IO que se capturan en RUNNABLE son todas problemáticas.

La siguiente pila muestra: El estado del hilo es RUNNABLE. La pila de llamadas está en SocketInputStream o SocketImpl, socketRead0 y otros métodos. La pila de llamadas contiene paquetes relacionados con jdbc. Es posible que se haya producido un interbloqueo de la base de datos


"d&a-614" daemon prio=6 tid=0x0000000022f1f000 nid=0x37c8 runnable
[0x0000000027cbd000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at oracle.net.ns.Packet.receive(Packet.java:240)
at oracle.net.ns.DataPacket.receive(DataPacket.java:92)
at oracle.net.ns.NetInputStream.getNextPacket(NetInputStream.java:172)
at oracle.net.ns.NetInputStream.read(NetInputStream.java:117)
at oracle.jdbc.driver.T4CMAREngine.unmarshalUB1(T4CMAREngine.java:1034)
at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:588)

Duerme con programación de hilos

Grupo de subprocesos normal en espera


"d&a-131" in Object.wait()
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at com.jiuqi.dna.core.impl.WorkingManager.getWorkToDo(WorkingManager.java:322)
- locked <0x0000000313f656f8> (a com.jiuqi.dna.core.impl.WorkingThread)
at com.jiuqi.dna.core.impl.WorkingThread.run(WorkingThread.java:40)

Hilo sospechoso en espera


"d&a-121" in Object.wait()
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at com.jiuqi.dna.core.impl.AcquirableAccessor.exclusive()
- locked <0x00000003011678d8> (a com.jiuqi.dna.core.impl.CacheGroup)
at com.jiuqi.dna.core.impl.Transaction.lock()

Resumen del punto de inicio

esperar en la entrada del monitor: bloqueado, debe haber un problema

ejecutable: preste atención al hilo IO

en Object.wait (): preste atención a la espera del grupo sin subprocesos

utilizar


Si quieres aprender un comando, primero mira la ayuda. Usa jstack -help para ver la ayuda:

hollis@hos:~$ jstack -help
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> 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

-F Obligar a imprimir la información de la pila cuando 'jstack [-l] pid' no corresponde. -L Lista larga. Imprime información adicional sobre bloqueos, como la lista de sincronizadores que se pueden poseer que pertenecen a java.util.concurrent. -M Imprime java y nativo c / c ++ framework toda la información de la pila.-h | -help Imprimir información de ayuda pid El id del proceso java que necesita ser impreso información de configuración, puede usar jps para consultar.

Primero, analizamos la situación del hilo de dicho programa:


/**
 * @author hollis
 */
public class JStackDemo1 {
    public static void main(String[] args) {
        while (true) {
            //Do Nothing
        }
    }
}

Primero, hay jps para ver el número de proceso:

hollis@hos:~$ jps
29788 JStackDemo1
29834 Jps
22385 org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar

Luego use jstack para ver la información de la pila:

hollis@hos:~$ jstack 29788
2015-04-17 23:47:31
...此处省略若干内容...
"main" prio=10 tid=0x00007f197800a000 nid=0x7462 runnable [0x00007f197f7e1000]
   java.lang.Thread.State: RUNNABLE
    at javaCommand.JStackDemo1.main(JStackDemo1.java:7)

¿Qué podemos ver de esta información de pila? Podemos ver que actualmente hay un hilo a nivel de usuario, que está en el estado ejecutable y se ejecuta en la séptima línea de JStackDemo1.java. Mira el siguiente código:


/**
 * @author hollis
 */
public class JStackDemo1 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Thread1());
        thread.start();
    }
}
class Thread1 implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println(1);
        }
    }
}

La información de la pila de subprocesos es la siguiente:

"Reference Handler" daemon prio=10 tid=0x00007fbbcc06e000 nid=0x286c in Object.wait() [0x00007fbbc8dfc000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x0000000783e066e0> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:503)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
    - locked <0x0000000783e066e0> (a java.lang.ref.Reference$Lock)

Podemos ver:

Estado del hilo: ESPERANDO la pila de llamadas del hilo Recursos actualmente bloqueados del hilo: <0x0000000783e066e0> hilo que está esperando recursos: <0x0000000783e066e0>

Por qué están esperando el mismo recurso bloqueado al mismo tiempo:

En la ejecución del hilo, primero se obtiene el Monitor de este objeto (correspondiente al bloqueado <0x0000000783e066e0>). Cuando la ejecución llega a obj.wait (), el hilo renuncia a la propiedad del Monitor y entra en la cola de "conjunto de espera" (correspondiente a esperar en <0x0000000783e066e0>).

Análisis de interbloqueo

Después de aprender a usar el comando jstack, podemos ver cómo usar jstack para analizar interbloqueos, esto es lo que debemos dominar. ¿Qué es un punto muerto? El llamado deadlock: se refiere a un fenómeno de bloqueo provocado por la competencia por los recursos o por la comunicación entre ellos durante la ejecución de dos o más procesos, si no hay fuerza externa no podrán avanzar. En este momento, se dice que el sistema se encuentra en un estado de interbloqueo o que el sistema tiene un interbloqueo Estos procesos que siempre están esperando el uno al otro se denominan procesos de interbloqueo. Para decirlo sin rodeos, quiero comer panqueques rellenos de huevo. Hay huevos y panqueques en la mesa, pero mi amigo y yo recogimos los huevos y enfermamos al mismo tiempo. Tengo huevos en mis manos, pero necesito los panqueques en sus manos. Tiene pan en la mano, pero quiere el huevo en la mía. De esta manera, si no podemos conseguir los huevos y el pastel al mismo tiempo, entonces no podemos continuar haciendo el siguiente trabajo (hacer un pastel relleno de huevo). Por tanto, esto provocó un punto muerto. Mira un programa bloqueado:

package javaCommand;
/**
 * @author hollis
 */
public class JStackDemo {
    public static void main(String[] args) {
        Thread t1 = new Thread(new DeadLockclass(true));//建立一个线程
        Thread t2 = new Thread(new DeadLockclass(false));//建立另一个线程
        t1.start();//启动一个线程
        t2.start();//启动另一个线程
    }
}
class DeadLockclass implements Runnable {
    public boolean falg;// 控制线程
    DeadLockclass(boolean falg) {
        this.falg = falg;
    }
    public void run() {
        /**
         * 如果falg的值为true则调用t1线程
         */
        if (falg) {
            while (true) {
                synchronized (Suo.o1) {
                    System.out.println("o1 " + Thread.currentThread().getName());
                    synchronized (Suo.o2) {
                        System.out.println("o2 " + Thread.currentThread().getName());
                    }
                }
            }
        }
        /**
         * 如果falg的值为false则调用t2线程
         */
        else {
            while (true) {
                synchronized (Suo.o2) {
                    System.out.println("o2 " + Thread.currentThread().getName());
                    synchronized (Suo.o1) {
                        System.out.println("o1 " + Thread.currentThread().getName());
                    }
                }
            }
        }
    }
}

class Suo {
    static Object o1 = new Object();
    static Object o2 = new Object();
}

Cuando inicio el programa, miramos la consola:
Serie de aprendizaje de comandos de Java (dos) -Jstack

Descubrimos que el programa solo imprime dos líneas, y luego el programa ya no imprime otras cosas, pero el programa no se detiene. Esto crea un punto muerto. Cuando el hilo 1 usa sincronizado para bloquear o1, el hilo 2 también usa sincronizado para bloquear o2. Cuando ambos subprocesos terminan la primera tarea de impresión, el subproceso 1 quiere bloquear o2 y el subproceso 2 quiere bloquear o1. Sin embargo, el hilo 1 bloquea actualmente o1 y el hilo 2 bloquea o2. Por lo tanto, los dos piensan que Chengdu no puede continuar la ejecución, lo que provocó un punto muerto.

Luego, usamos jstack para ver la información de la pila de subprocesos:

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f0134003ae8 (object 0x00000007d6aa2c98, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f0134006168 (object 0x00000007d6aa2ca8, a java.lang.Object),
  which is held by "Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
    at javaCommand.DeadLockclass.run(JStackDemo.java:40)
    - waiting to lock <0x00000007d6aa2c98> (a java.lang.Object)
    - locked <0x00000007d6aa2ca8> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:745)
"Thread-0":
    at javaCommand.DeadLockclass.run(JStackDemo.java:27)
    - waiting to lock <0x00000007d6aa2ca8> (a java.lang.Object)
    - locked <0x00000007d6aa2c98> (a java.lang.Object)
    at java.lang.Thread.run(Thread.java:745)

Found 1 deadlock.

Jaja, la pila está claramente escrita, nos dice Encontrado un punto muerto en el nivel de Java y luego señala el contenido de los dos hilos que causaron el punto muerto. Luego, a través de la información de la pila de Java de los subprocesos enumerados anteriormente para mostrar información de interbloqueo más detallada. Él dijo

Cuando Thread-1 quiere ejecutar la línea 40, actualmente bloquea el recurso <0x00000007d6aa2ca8>, pero está esperando el recurso <0x00000007d6aa2c98>. Cuando Thread-0 quiere ejecutar la línea 27, actualmente bloquea el recurso <0x00000007d6aa2c98 >, pero está esperando recursos <0x00000007d6aa2ca8> Debido a que estos dos subprocesos contienen recursos y ambos necesitan recursos el uno del otro, se produce un interbloqueo. Si encontramos el motivo, podemos analizar el problema específico y solucionar el punto muerto.

otro

Cuando la máquina virtual ejecuta Full GC, bloqueará todos los subprocesos del usuario. Por lo tanto, el subproceso que adquiere inmediatamente el bloqueo de sincronización también puede bloquearse. Al ver el volcado de subprocesos, primero observe el uso de la memoria.

Supongo que te gusta

Origin blog.51cto.com/13626762/2545872
Recomendado
Clasificación