• ¡Obtenga la seguridad de la aplicación de la manera correcta! Detectar, proteger, monitorear, acelerar y más ...
  • Hablemos sobre el volcado de hilos y cómo analizarlo.

    También discutiremos cómo ayuda identificar los problemas y algunos de los analizadores que puede usar.

    ¿Qué es Thread?

    Un proceso es un programa de computadora que se carga en la memoria de la computadora y está en ejecución. Puede ser ejecutado por un procesador o un conjunto de procesadores. Un proceso se describe en la memoria con información importante como almacenes de variables, identificadores de archivos, contador de programa, registros y señales, etc.

    Un proceso puede constar de muchos procesos ligeros denominados hilos. Esto ayuda a lograr un paralelismo en el que un proceso se divide en varios subprocesos. Esto da como resultado un mejor rendimiento. Todos los subprocesos de un proceso comparten el mismo espacio de memoria y dependen unos de otros.

    Volcados de hilo

    Cuando el proceso se está ejecutando, podemos detectar el estado actual de ejecución de los subprocesos en el proceso usando volcados de hilo. Un volcado de subprocesos contiene una instantánea de todos los subprocesos activos en un punto particular durante la ejecución de un programa. Contiene toda la información relevante sobre el hilo y su estado actual.

    Hoy en día, una aplicación moderna implica varios subprocesos. Cada hilo requiere ciertos recursos, realiza ciertas actividades relacionadas con el proceso. Esto puede aumentar el rendimiento de una aplicación, ya que los subprocesos pueden utilizar los núcleos de CPU disponibles.

    Pero hay compensaciones, por ejemplo, a veces varios subprocesos pueden no coordinarse bien entre sí y puede surgir una situación de punto muerto. Entonces, si algo sale mal, podemos usar volcados de subprocesos para inspeccionar el estado de nuestros subprocesos.

    Volcado de hilo en Java

    Un volcado de subprocesos de JVM es una lista del estado de todos los subprocesos que forman parte del proceso en ese momento específico. Contiene información sobre la pila del hilo, presentada como un seguimiento de pila. Como está escrito en texto plano, el contenido se puede guardar para revisarlo más tarde. El análisis de volcados de subprocesos puede ayudar

    • Optimización del rendimiento de JVM
    • Optimización del rendimiento de la aplicación
    • Diagnóstico de problemas, por ejemplo, un punto muerto, contención de subprocesos, etc.

    Generación de volcados de hilo

    Hay muchas formas de generar volcados de subprocesos. A continuación se muestran algunas herramientas basadas en JVM y se pueden ejecutar desde la línea de comandos / terminal (herramientas CLI) o /compartimiento (Herramientas GUI) directorio de la carpeta de instalación de Java.

    Explorémoslos.

    #1. jStack

    La forma más sencilla de generar un volcado de subprocesos es mediante jStack. jStack se envía con JVM y se puede usar desde la línea de comandos. Aquí, necesitamos el PID del proceso para el que queremos generar el volcado de hilo. Para obtener PID podemos usar jps comando como se muestra a continuación.

    jps -l

    jps enumera todos los identificadores de procesos de Java.

    En Windows

    C:\Program Files\Java\jdk1.8.0_171\bin>jps -l
    47172 portal
    6120 sun.tools.jps.Jps
    C:\Program Files\Java\jdk1.8.0_171\bin>

    En Linux

    [[email protected] ~]# jps -l
    1088 /opt/keycloak/jboss-modules.jar
    26680 /var/lib/jenkins/workspace/kyc/kyc/target/kyc-1.0.jar
    7193 jdk.jcmd/sun.tools.jps.Jps
    2058 /usr/share/jenkins/jenkins.war
    11933 /var/lib/jenkins/workspace/admin-portal/target/portal-1.0.jar
    [[email protected] ~]#
    

    Como podemos ver aquí, obtenemos una lista de todos los procesos de Java en ejecución. Contiene el ID de VM local para el proceso de Java en ejecución y el nombre de la aplicación en las columnas uno y dos, respectivamente. Ahora, para generar el volcado de hilo, usamos el jStack programa con Lo bandera que crea una salida larga del volcado. También podemos canalizar la salida a algún archivo de texto de nuestra elección.

    jstack -l 26680

    [[email protected] ~]# jstack -l 26680
    2020-06-27 06:04:53
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):
    
    "Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
            - None
    
    "logback-8" #2316 daemon prio=5 os_prio=0 tid=0x00007f07e0033000 nid=0x4792 waiting on condition [0x00007f07baff8000]
       java.lang.Thread.State: WAITING (parking)
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
            at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
            at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
            at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at java.lang.Thread.run(Thread.java:748)
    
       Locked ownable synchronizers:
            - None
    
    "logback-7" #2315 daemon prio=5 os_prio=0 tid=0x00007f07e0251800 nid=0x4791 waiting on condition [0x00007f07bb0f9000]
       java.lang.Thread.State: WAITING (parking)
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x00000006ca9a1fc0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
            at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
            at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
            at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
            at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at java.lang.Thread.run(Thread.java:748)
    
       Locked ownable synchronizers:
            - None

    #2. jvisualvm

    Jvisualvm es una herramienta GUI que nos ayuda a solucionar problemas, monitorear y perfilar aplicaciones Java. También viene con JVM y se puede iniciar desde el /compartimiento directorio de nuestra instalación de java. Es muy intuitivo y fácil de usar. Entre otras opciones, también nos permite capturar el volcado de subprocesos para un proceso en particular.

    Para ver el volcado de hilo para un proceso en particular, podemos hacer clic derecho en el programa y seleccionar Volcado de hilo desde el menú contextual.

    #3. jcmd

    JCMD es una utilidad de línea de comandos que se incluye con el JDK y se utiliza para enviar solicitudes de comando de diagnóstico a la JVM.

    Sin embargo, solo funciona en la máquina local donde se ejecuta la aplicación Java. Se puede utilizar para controlar las grabaciones de vuelo de Java, diagnosticar y solucionar problemas de aplicaciones Java y JVM. Podemos usar el Thread.print comando de jcmd para obtener una lista de volcados de subprocesos para un proceso en particular especificado por el PID.

    A continuación se muestra un ejemplo de cómo podemos usar jcmd.

    jcmd 28036 Thread.print

    C:\Program Files\Java\jdk1.8.0_171\bin>jcmd 28036 Thread.print
    28036:
    2020-06-27 21:20:02
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode):
    
    "Bundle File Closer" #14 daemon prio=5 os_prio=0 tid=0x0000000021d1c000 nid=0x1d4c in Object.wait() [0x00000000244ef000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            at java.lang.Object.wait(Unknown Source)
            at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.getNextEvent(EventManager.java:403)
            - locked <0x000000076f380a88> (a org.eclipse.osgi.framework.eventmgr.EventManager$EventThread)
            at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread.run(EventManager.java:339)
    
    "Active Thread: Equinox Container: 0b6cc851-96cd-46de-a92b-253c7f7671b9" #12 prio=5 os_prio=0 tid=0x0000000022e61800 nid=0xbff4 waiting on condition [0x00000000243ee000]
       java.lang.Thread.State: TIMED_WAITING (parking)
            at sun.misc.Unsafe.park(Native Method)
            - parking to wait for  <0x000000076f388188> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
            at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
            at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
            at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
            at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
            at java.lang.Thread.run(Unknown Source)
    
    "Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000021a7b000 nid=0x2184 runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "C1 CompilerThread3" #9 daemon prio=9 os_prio=2 tid=0x00000000219f5000 nid=0x1300 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "C2 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000219e0000 nid=0x48f4 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x00000000219df000 nid=0xb314 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x00000000219db800 nid=0x2260 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x00000000219d9000 nid=0x125c waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x00000000219d8000 nid=0x834 runnable [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
    "Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001faf3000 nid=0x36c0 in Object.wait() [0x0000000021eae000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(Unknown Source)
            - locked <0x000000076f390180> (a java.lang.ref.ReferenceQueue$Lock)
            at java.lang.ref.ReferenceQueue.remove(Unknown Source)
            at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
    
    "Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000005806000 nid=0x13c0 in Object.wait() [0x00000000219af000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            - waiting on <0x000000076f398178> (a java.lang.ref.Reference$Lock)
            at java.lang.Object.wait(Unknown Source)
            at java.lang.ref.Reference.tryHandlePending(Unknown Source)
            - locked <0x000000076f398178> (a java.lang.ref.Reference$Lock)
            at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
    
    "main" #1 prio=5 os_prio=0 tid=0x000000000570e800 nid=0xbf8 runnable [0x0000000000fec000]
       java.lang.Thread.State: RUNNABLE
            at java.util.zip.ZipFile.open(Native Method)
            at java.util.zip.ZipFile.<init>(Unknown Source)
            at java.util.zip.ZipFile.<init>(Unknown Source)
            at java.util.zip.ZipFile.<init>(Unknown Source)
            at org.eclipse.osgi.framework.util.SecureAction.getZipFile(SecureAction.java:307)
            at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getZipFile(ZipBundleFile.java:136)
            at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.lockOpen(ZipBundleFile.java:83)
            at org.eclipse.osgi.storage.bundlefile.ZipBundleFile.getEntry(ZipBundleFile.java:290)
            at org.eclipse.equinox.weaving.hooks.WeavingBundleFile.getEntry(WeavingBundleFile.java:65)
            at org.eclipse.osgi.storage.bundlefile.BundleFileWrapper.getEntry(BundleFileWrapper.java:55)
            at org.eclipse.osgi.storage.BundleInfo$Generation.getRawHeaders(BundleInfo.java:130)
            - locked <0x000000076f85e348> (a java.lang.Object)
            at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:599)
            at org.eclipse.osgi.storage.BundleInfo$CachedManifest.get(BundleInfo.java:1)
            at org.eclipse.equinox.weaving.hooks.SupplementerRegistry.addSupplementer(SupplementerRegistry.java:172)
            at org.eclipse.equinox.weaving.hooks.WeavingHook.initialize(WeavingHook.java:138)
            at org.eclipse.equinox.weaving.hooks.WeavingHook.start(WeavingHook.java:208)
            at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startActivator(FrameworkExtensionInstaller.java:261)
            at org.eclipse.osgi.storage.FrameworkExtensionInstaller.startExtensionActivators(FrameworkExtensionInstaller.java:198)
            at org.eclipse.osgi.internal.framework.SystemBundleActivator.start(SystemBundleActivator.java:112)
            at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:815)
            at org.eclipse.osgi.internal.framework.BundleContextImpl$3.run(BundleContextImpl.java:1)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.eclipse.osgi.internal.framework.BundleContextImpl.startActivator(BundleContextImpl.java:808)
            at org.eclipse.osgi.internal.framework.BundleContextImpl.start(BundleContextImpl.java:765)
            at org.eclipse.osgi.internal.framework.EquinoxBundle.startWorker0(EquinoxBundle.java:1005)
            at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle$EquinoxSystemModule.initWorker(EquinoxBundle.java:190)
            at org.eclipse.osgi.container.SystemModule.init(SystemModule.java:99)
            at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:272)
            at org.eclipse.osgi.internal.framework.EquinoxBundle$SystemBundle.init(EquinoxBundle.java:257)
            at org.eclipse.osgi.launch.Equinox.init(Equinox.java:171)
            at org.eclipse.core.runtime.adaptor.EclipseStarter.startup(EclipseStarter.java:316)
            at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:251)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:661)
            at org.eclipse.equinox.launcher.Main.basicRun(Main.java:597)
            at org.eclipse.equinox.launcher.Main.run(Main.java:1476)
    
    "VM Thread" os_prio=2 tid=0x000000001fae8800 nid=0x32cc runnable
    
    "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000005727800 nid=0x3264 runnable
    
    "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000005729000 nid=0xbdf4 runnable
    
    "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000572a800 nid=0xae6c runnable
    
    "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000572d000 nid=0x588 runnable
    
    "GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000572f000 nid=0xac0 runnable
    
    "GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000005730800 nid=0x380 runnable
    
    "GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000000005733800 nid=0x216c runnable
    
    "GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000000005734800 nid=0xb930 runnable
    
    "VM Periodic Task Thread" os_prio=2 tid=0x0000000021a8d000 nid=0x2dcc waiting on condition
    
    JNI global references: 14
    
    
    C:\Program Files\Java\jdk1.8.0_171\bin>

    #4. JMC

    JMC significa Control de misión de Java. Es una herramienta GUI de código abierto que se envía con JDK y se utiliza para recopilar y analizar datos de aplicaciones Java.

    Se puede iniciar desde /compartimiento carpeta de nuestra instalación de Java. Los administradores y desarrolladores de Java utilizan la herramienta para recopilar información detallada de bajo nivel sobre los comportamientos de la aplicación y la JVM. Permite un análisis detallado y eficiente de los datos recopilados por Java. Grabador de vuelo.

    Al lanzar jmc, podemos ver la lista de procesos de Java que se están ejecutando en la máquina local. También es posible una conexión remota. En un proceso en particular, podemos hacer clic derecho y elegir Iniciar grabación de vuelo y luego verifique los volcados de hilo en el Temas lengüeta.

    #5. jconsole

    jconsole es una herramienta de extensión de gestión de Java que se utiliza para la gestión y el seguimiento de quejas.

    También tiene un conjunto de operaciones predefinidas en el agente JMX que el usuario puede realizar. Permite al usuario detectar y analizar el seguimiento de la pila de un programa en vivo. Se puede iniciar desde /compartimiento carpeta de nuestra instalación de Java.

    Usando el patrón de velas del jconsole Con la herramienta GUI podemos inspeccionar el seguimiento de la pila de cada hilo cuando lo conectamos a un proceso Java en ejecución. Luego, en la pestaña Subproceso, podemos ver el nombre de todos los subprocesos en ejecución. Para detectar un interbloqueo, podemos hacer clic en el Detectar interbloqueo en la parte inferior derecha de la ventana. Si se detecta un interbloqueo, aparecerá en una nueva pestaña. No se detectó interbloqueo será mostrado.

    #6. ThreadMxBean

    ThreadMXBean es la interfaz para la gestión del sistema de subprocesos de la máquina virtual Java perteneciente al paquete java.lang.Management. Se utiliza principalmente para detectar los subprocesos que han entrado en una situación de bloqueo y obtener detalles sobre ellos.

    Podemos usar la interfaz ThreadMxBean para capturar programáticamente el volcado del hilo. getThreadMXBean() método de ManagementFactory se usa para obtener una instancia del ThreadMXBean interfaz. Devuelve el número de subprocesos en vivo tanto daemon como no daemon. ManagementFactory es una clase de fábrica para obtener los beans administrados para la plataforma Java.

    private static String getThreadDump (boolean lockMonitors, boolean lockSynchronizers) {
        StringBuffer threadDump = new StringBuffer (System.lineSeparator ());
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean ();
        for (ThreadInfo threadInfo : threadMXBean.dumpAllThreads (lockMonitors, lockSynchronizers)) {
            threadDump.append (threadInfo.toString ());
        }
        return threadDump.toString ();
    }

    Análisis manual de volcados de hilo

    El análisis de volcados de subprocesos puede ser muy útil para identificar problemas en procesos multiproceso. Los problemas como los puntos muertos, la contención de bloqueos y el uso excesivo de CPU por volcados de subprocesos individuales se pueden resolver visualizando los estados de los volcados de subprocesos individuales.

    El rendimiento máximo de la aplicación se puede lograr rectificando el estado de cada hilo después de analizar el volcado del hilo.

    En el, digamos, un proceso está usando mucha CPU, podemos averiguar si algún subproceso está usando más la CPU. Si existe alguno de esos hilos, convertimos su número LWP en un número hexadecimal. Luego, desde el volcado del hilo, podemos encontrar el hilo con un nid igual al número hexadecimal obtenido previamente. Usando el seguimiento de la pila del hilo, podemos identificar el problema. Averigüemos el ID de proceso del hilo usando el siguiente comando.

    ps -mo pid,lwp,stime,time,cpu -C java

    [[email protected] ~]# ps -mo pid,lwp,stime,time,cpu -C java
           PID        LWP         STIME           TIME              %CPU
    26680               -         Dec07          00:02:02           99.5
             -       10039        Dec07          00:00:00           0.1
             -       10040        Dec07          00:00:00           95.5
    

    Echemos un vistazo a la parte de abajo del volcado de hilo. Para obtener el volcado de subprocesos para el proceso 26680, utilice jstack -l 26680

    [[email protected] ~]# jstack -l 26680
    2020-06-27 09:01:29
    <strong>Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):</strong>
    
    "Attach Listener" #16287 daemon prio=9 os_prio=0 tid=0x00007f0814001800 nid=0x4ff2 waiting on condition [0x0000000000000000]
       java.lang.Thread.State: RUNNABLE
    
       Locked ownable synchronizers:
            - None
    
    .
    .
    .
    .
    .
    .
    .
    "<strong>Reference Handler</strong>" #2 daemon prio=10 os_prio=0 tid=0x00007f085814a000 nid=0x6840 in Object.wait() [0x00007f083b2f1000]
       java.lang.Thread.State: WAITING (on object monitor)
            at java.lang.Object.wait(Native Method)
            at java.lang.Object.wait(Object.java:502)
            at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
            - locked <0x00000006c790fbd0> (a java.lang.ref.Reference$Lock)
            at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
    
       Locked ownable synchronizers:
            - None
    
    "VM Thread" os_prio=0 tid=0x00007f0858140800 nid=0x683f runnable
    
    "GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f0858021000 nid=0x683b runnable
    
    "GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f0858022800 nid=0x683c runnable
    
    "GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f0858024800 nid=0x683d runnable
    
    "GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f0858026000 nid=0x683e runnable
    
    "VM Periodic Task Thread" os_prio=0 tid=0x00007f08581a0000 nid=0x6847 waiting on condition
    
    JNI global references: 1553
    

    Ahora, veamos cuáles son las cosas que podemos explorar usando volcados de hilo. Si observamos el volcado de subprocesos, podemos ver una gran cantidad de contenido, que puede resultar abrumador. Sin embargo, si damos un paso a la vez, puede ser bastante sencillo de entender. Entendamos la primera línea

    2020-06-27 09:01:29
    Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.221-b11 mixed mode):

    Lo anterior muestra la hora en que se generó el volcado y la información sobre la JVM que se utilizó. A continuación, al final, podemos ver la lista de hilos, el primero de ellos es nuestro ReferenceHandler hilo.

    Análisis de subprocesos bloqueados

    Si analizamos los registros de volcado de subprocesos a continuación, podemos encontrar que ha detectado subprocesos con OBSTRUIDO estado que hace que el rendimiento de una aplicación sea muy lento. Entonces, si podemos encontrar el OBSTRUIDO hilos, podemos intentar extraer los hilos relacionados con los bloqueos que los hilos están intentando obtener. El análisis del seguimiento de la pila desde el hilo que actualmente sostiene el bloqueo puede ayudar a resolver el problema.

    [[email protected] ~]# jstack -l 26680
    .
    .
    .
    .
    " DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
    java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
                    at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                    - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                    at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                    at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
    "DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
    java.lang.Thread.State: <strong>BLOCKED</strong> (on object monitor)
                    at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
                    - waiting to lock <0xe0375410> (a beans.ConnectionPool)
                    at beans.cus.ServiceCnt.getTodayCount(ServiceCnt.java:111)
                    at beans.cus.ServiceCnt.insertCount(ServiceCnt.java:43)
    .
    .
    .
    .

    Analizando hilo interbloqueado

    Otra aplicación muy utilizada de volcados de subprocesos es la detección de puntos muertos. La detección y solución de interbloqueos puede ser mucho más sencilla si analizamos los volcados de subprocesos.

    Un interbloqueo es una situación que involucra al menos dos subprocesos en la que el recurso requerido por un subproceso para continuar la ejecución está bloqueado por otro subproceso y, al mismo tiempo, el recurso requerido por el segundo subproceso está bloqueado por el primer subproceso.

    Por lo tanto, ninguno de los subprocesos puede continuar la ejecución, y esto da como resultado una situación de interbloqueo y termina con la aplicación atascada. Si hay rastas, la sección final del volcado de hilo imprimirá la información sobre el punto muerto de la siguiente manera.

    "Thread-0":
    waiting to lock monitor 0x00000250e4982480 (object 0x00000000894465b0, a java.lang.Object),
    which is held by "Thread-1"
    "Thread-1":
    waiting to lock monitor 0x00000250e4982380 (object 0x00000000894465a0, a java.lang.Object),
    which is held by "Thread-0"
    .
    .
    .
    "Thread-0":
    at DeadlockedProgram$DeadlockedRunnableImplementation.run(DeadlockedProgram.java:34)
    - waiting to lock <0x00000000894465b0> (a java.lang.Object)
    - locked <0x00000000894465a0> (a java.lang.Object)
    at java.lang.Thread.run([email protected]/Thread.java:844)
    "Thread-1":
    at DeadlockedProgram $DeadlockRunnableImplementation.run(DeadlockedProgram.java:34)
    - waiting to lock <0x00000000894465a0> (a java.lang.Object)
    - locked <0x00000000894465b0> (a java.lang.Object)
    at java.lang.Thread.run([email protected]/Thread.java:844)

    Aquí podemos ver la información del interbloqueo en un formato bastante legible por humanos.

    Aparte de esto, si sumamos todo el fragmento anterior de volcado de subprocesos juntos, entonces indica la siguiente información.

    • Controlador de referencia es el nombre legible por humanos del hilo.
    • #2 es la identificación única del hilo.
    • demonio denota si el hilo es un hilo demonio.
    • La prioridad numérica del hilo viene dada por prio= 10.
    • El estado actual del hilo se denota por esperando en condición.
    • Luego vemos el seguimiento de la pila, que incluye la información de bloqueo.

    Analizadores de volcado de hilo

    Además del análisis manual, existen numerosas herramientas disponibles para analizar volcados de subprocesos, tanto en línea como fuera de línea. A continuación se muestran algunas de las herramientas enumeradas, que podemos utilizar en función de los requisitos.

    Primero, exploremos las herramientas en línea.

    #1. Hilo rápido

    Hilo rápido es la DevOps la herramienta de análisis de volcado de hilo favorita de los ingenieros para solucionar problemas complejos de producción. Este es un analizador de volcado de subprocesos de Java en línea. Podemos cargar el volcado de subprocesos como un archivo o podemos copiar y pegar directamente el volcado de subprocesos.

    Dependiendo del tamaño, analizará el volcado del hilo y mostrará la información como se muestra en la captura de pantalla.

    Caracteristicas

    • Solucionar fallas de JVM, ralentizaciones, fugas de memoria, congelamientos, picos de CPU
    • RCA instantáneo (no espere a los proveedores)
    • Tablero de instrumentos intuitivo
    • Soporte de API REST
    • Aprendizaje automático

    #2. Analizador de volcado de hilos de Spotify

    La Analizador de volcado de hilos de Spotify tiene la licencia de la versión 2.0 de la licencia Apache. Es una herramienta en línea y acepta el volcado de hilo como un archivo o podemos copiar y pegar directamente el volcado de hilo. Dependiendo del tamaño, analizará el volcado del hilo y mostrará la información como se muestra en la captura de pantalla.

    #3. Revisión de Jstack

    Jstack.review analiza los volcados de subprocesos de Java desde el navegador. Esta página es solo del lado del cliente.

    #4. Sitio web 24 × 7

    Esta historia de herramienta es un requisito previo para detectar subprocesos defectuosos que degraden el rendimiento de la máquina virtual Java (JVM). Los problemas como los puntos muertos, la contención de bloqueos y el uso excesivo de CPU por volcados de subprocesos individuales se pueden resolver visualizando los estados de los volcados de subprocesos individuales.

    El rendimiento máximo de la aplicación se puede lograr rectificando el estado de cada hilo proporcionado por la herramienta.

    Ahora, exploremos las herramientas sin conexión.

    Cuando se trata de crear perfiles, solo la mejor herramienta es suficientemente buena.

    #1. JProfiler

    JProfiler es uno de los analizadores de volcado de subprocesos más populares entre Desarrolladores de Java. La interfaz de usuario intuitiva de JProfiler lo ayuda a resolver cuellos de botella de rendimiento, identificar pérdidas de memoria y comprender los problemas de subprocesos.

    JProfiler

    JProfiler admite la creación de perfiles en las siguientes plataformas:

    • Windows
    • MacOS
    • Linux
    • FreeBSD
    • Solaris
    • AIX
    • HP-UX

    A continuación se muestran algunas características que hacen de JProfiler la mejor opción para perfilar nuestras aplicaciones en la JVM.

    Caracteristicas

    • Admite la creación de perfiles de bases de datos para JDBC, JPA y NoSQL
    • También está disponible el soporte para la edición empresarial de Java
    • Presenta información de alto nivel sobre llamadas RMI
    • Análisis estelar de fugas de memoria
    • Amplias capacidades de control de calidad
    • El perfilador de subprocesos integrado está estrechamente integrado con las vistas de perfilado de la CPU.
    • Soporte para plataformas, IDE y servidores de aplicaciones.

    #2. IBM TMDA

    IBM Thread and Monitor Dump Analyzer para Java (TMDA) es una herramienta que permite la identificación de bloqueos, interbloqueos, contención de recursos y cuellos de botella en volcados de subprocesos de Java. Es un producto de IBM, pero la herramienta TMDA se proporciona sin garantía ni soporte; sin embargo, intentan arreglar y mejorar la herramienta con el tiempo.

    #3. ManageEngine

    ManageEngine El administrador de aplicaciones puede ayudar a monitorear la memoria Heap y Non-Heap de JVM. Incluso podemos configurar umbrales y recibir alertas por correo electrónico, SMS, etc., y asegurarnos de que una aplicación Java esté bien ajustada.

    #4. YourKit

    YourKit consta de los siguientes productos denominados Kit.

    • Java Profiler: generador de perfiles de baja sobrecarga con todas las funciones para las plataformas Java EE y Java SE.
    • YouMonitor: supervisión del rendimiento y creación de perfiles de Jenkins, TeamCity, Gradle, Maven, Ant, JUnit y TestNG.
    • .NET Profiler: perfilador de memoria y rendimiento fácil de usar para .NET framework.

    Conclusión

    Ahora ya sabe cómo los volcados de subprocesos son útiles para comprender y diagnosticar problemas en aplicaciones multiproceso. Con la debida conocimientos, con respecto a los volcados de subprocesos (su estructura, la información que contienen, etc.), podemos utilizarlos para identificar las causas de los problemas rápidamente.