4. Comenzando desde cero, maestro práctico de JVM: monitoreo de JVM y ubicación de problemas en línea

prefacio

Los programadores de Java que entrevistan a JVM son casi más difíciles que hacer preguntas. A menudo se hacen preguntas como el monitoreo de JVM, OOM en línea y la carga de la CPU al 100%. Aunque puede que no sea nuestro turno para tratar los problemas en línea en las empresas, ya sea para entrevistas o Para hacer frente al desarrollo, es necesario comprender el manejo de problemas en línea de JVM.

Hablando en términos relativos, ya sea para resolver el problema de falla o lidiar con los cuellos de botella de rendimiento, la idea general es más o menos la misma, es decir: analizar datos (registros), analizar y solucionar problemas, localizar problemas y resolver problemas. datos o registros de ejecución Si no podemos obtenerlos, entonces no tenemos manera de localizar el problema.

Afortunadamente, Java ha enviado herramientas de monitoreo de JVM e instrucciones relacionadas para ayudarnos a obtener datos relacionados con JVM para ayudarnos a solucionar problemas.

instalación de herramientas

Solo sabemos que existe una JVM, pero su funcionamiento nos parece invisible, por lo que necesitamos herramientas para monitorear su estado en tiempo real, al igual que el monitor de rendimiento de Windows, JDK también tiene sus propias herramientas de visualización.Java proporciona 2 herramientas de monitoreo. :

  • D:\opensource\jdk1.8\bin\jconsole.exe

  • D:\opensource\jdk1.8\bin\jvisualvm.exe

jconsole

Ingrese jconsole a través de la línea de comando cmd y aparecerá la siguiente interfaz
inserte la descripción de la imagen aquí
. Seleccione java para ingresar y podrá ver el estado de la memoria, el estado de carga de la clase, el estado del hilo, etc. después de ingresar.
inserte la descripción de la imagen aquí

jvisualvm

Ejecutamos cmd, ingresamos jvisualvm e iniciamos Java VisualVM.
inserte la descripción de la imagen aquí
El menú local a la izquierda es el proceso java. Después de seleccionar un proceso, puede ver el montón, el estado de carga de la clase y el estado listo a la derecha.

jvisualvm instala el complemento GC

El jvisualvm incorporado no supervisa la función de recolección de basura de GC, necesitamos instalar complementos adicionales:

Abra Herramientas -> Complementos -> Seleccione la página "Complementos disponibles": Instalamos un Visual GC aquí, para que podamos ver la recuperación de la memoria y el estado de cada generación. Después de marcarlo, haga clic en Instalar, que es el siguiente normal y estar de acuerdo con el acuerdo, etc. La red no es muy estable, a veces puede tomar algunos intentos más. Puede modificar la dirección del centro de complementos en la configuración:

inserte la descripción de la imagen aquí

Modifique la dirección de acuerdo con los siguientes pasos: Encuentre el centro de complementos

http://visualvm.github.io/pluginscenters.html

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-EY48yUBo-1683959030847) (imagen del curso/wps3517.tmp.jpg)]

Encuentre la versión de JDK correspondiente:

http://visualvm.github.io/archive/uc/8u40/updates.htmlCopiar
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-GzJYYDpg-1683959030848) (imagen del curso/1638788437854.png)]
la dirección del complemento:
[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-0IxXMl7y-1683959030849) (imagen del curso/1638788450829.png)]

Instale el complemento:

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo de enlace antirrobo, se recomienda guardar la imagen y cargarla directamente (img-uApLHY5r-1683959030849) (imagen del curso/1638788458616.png)]

Luego busque Visual GC en los complementos disponibles

Una vez completada la instalación, cerramos la página de monitoreo actual, la abrimos nuevamente y puede ver que hay una página adicional de Visual GC detrás de Profiler.

[Falló la transferencia de la imagen del enlace externo, el sitio de origen puede tener un mecanismo anti-leeching, se recomienda guardar la imagen y cargarla directamente (img-q7SZdcnx-1683959030850) (imagen del curso/1638788466690.png)]

Aquí podemos ver el tiempo de actividad de JIT, el tiempo de actividad de carga de clases, el tiempo de actividad de GC y la situación de cada generación.

Cabe señalar que la versión de JDK utilizada por el material didáctico actual es 1.8, que aún viene con VisualVM. La versión a partir de 1.9 no viene con él y debe descargarse adicionalmente. La dirección de github para la descarga es:

https://visualvm.github.io/download.html

Además, si la herramienta de desarrollo usa Intellij IDEA, puede descargar un complemento, VisualVM Launcher, y puede ir directamente a la página anterior a través del inicio del complemento, sin buscar su propio proyecto en la entrada de la izquierda.

Por supuesto, hay otras herramientas, pero este será el desarrollo principal de la herramienta de manejo de fallas todo en uno en el futuro previsible. Por lo tanto, usaremos esta herramienta para analizar nuestra operación JVM y optimizarla más adelante. Para optimizar, también es necesario tener una mayor comprensión de la composición de la JVM

Comando de supervisión de JVM

En el entorno de producción, a menudo nos encontramos con varios problemas de rendimiento extraños. Podemos usar los comandos de monitoreo de JVM proporcionados por Java para lograr efectos de monitoreo y visualización. Los comandos relacionados son los siguientes

nombre efecto principal
jps Ver procesos Java en ejecución
jstack instantánea de hilo de impresión
jmap Exportar archivo de imagen de memoria de almacenamiento dinámico
estar de pie Ver estadísticas de jvm
jinfo Ver y modificar los parámetros de configuración de jvm en tiempo real
jajaja Se utiliza para analizar archivos de volcado de pila

jps ver el progreso

jps puede enumerar los procesos Java en ejecución y mostrar el nombre de la clase principal (clase principal, la clase donde se encuentra la función main()) de la máquina virtual y la identificación del proceso, y los parámetros se pueden ver a través de jps -help

opciones efecto
-q Solo muestra la identificación del proceso
-metro Salida de los parámetros pasados ​​​​a la función principal de la clase principal
-l Muestra el nombre de clase completo de la clase principal, si el proceso ejecuta el paquete Jar, muestra el nombre del paquete jar
-v El parámetro jvm especificado cuando se inicia el programa

Presentación del caso:
inserte la descripción de la imagen aquí

jstack: imprimir instantánea de hilo

Por lo general, en el entorno de producción, si se producen problemas como pausas prolongadas, atascos, interbloqueos y tiempos de solicitud prolongados, puede analizar y localizar el problema imprimiendo instantáneas de subprocesos. El siguiente es un código de interbloqueo:

public class DeadlockExample {
    
    
    private static Object lock1 = new Object();
    private static Object lock2 = new Object();
     public static void main(String[] args) {
    
    
        Thread t1 = new Thread() {
    
    
            public void run() {
    
    
                synchronized (lock1) {
    
    
                    System.out.println("Thread 1 acquired lock 1");
                    try {
    
    
                        Thread.sleep(1000);
                        synchronized (lock2) {
    
    
                            System.out.println("Thread 1 acquired lock 2");
                        }
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        };
         Thread t2 = new Thread() {
    
    
            public void run() {
    
    
                synchronized (lock2) {
    
    
                    System.out.println("Thread 2 acquired lock 2");
                    try {
    
    
                        Thread.sleep(1000);
                        synchronized (lock1) {
    
    
                            System.out.println("Thread 2 acquired lock 1");
                        }
                    } catch (InterruptedException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        };
         t1.start();
         t2.start();
         try {
    
    
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }
}

Luego intentamos jps -l para ver el proceso primero
inserte la descripción de la imagen aquí
, obtener la identificación del proceso y usar jstack para ver cada instantánea de subproceso: jstack 27928
inserte la descripción de la imagen aquí
Desde la instantánea de subproceso, puede ver todos los subprocesos en el proceso actual. Entre ellos están los hilos de nuestro código, y el estado está bloqueado. Al mismo tiempo, solicita encontrado 1 interbloqueo para encontrar un interbloqueo y brinda la ubicación donde ocurrió el interbloqueo.

jmap: exportar instantánea de montón

La ejecución jmap -histo pidpuede imprimir el número de instancias y el uso de memoria de cada clase en el montón actual, de la siguiente manera, el nombre de clase es el nombre de clase de cada clase ([B es tipo byte, [C es tipo char, [I es tipo int) , bytes Es el tamaño de memoria ocupado por todos los ejemplos de esta clase, e instancias es el número de instancias de esta clase:
inserte la descripción de la imagen aquí
ejecute jmap -dump para volcar la instantánea de la memoria del montón en un archivo específico, como ejecutar

jmap -dump:format=b,file=/data/jvm/dumpfile_jmap.hprof PID, puede volcar la instantánea de la memoria del montón actual en el archivo dumpfile_jmap.hprof y luego analizar la instantánea de la memoria.

Por lo general, configuramos el entorno de producción para que la máquina virtual genere automáticamente un archivo de volcado después de que ocurra una excepción OOM.

-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/Users

Por ejemplo, hay un bucle infinito de código y ejecutarlo durante un cierto período de tiempo provocará un desbordamiento de memoria.

public class Main {
    
    
    public static void main(String[] args) {
    
    
        ArrayList arrayList = new ArrayList();
        int i = 0;
        while(true){
    
    
            arrayList.add(new Main());
            System.out.println(i++);
        }
    }
}

Para el efecto obvio, configuramos el montón para que sea más pequeño y luego configuramos HeapDumpOnOutOfMemoryError en

-Xms2m
-Xmx2m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=d:\

Establezca los parámetros de VM anteriores para la aplicación actual, y el efecto de ejecutar el código es el siguiente
inserte la descripción de la imagen aquí
Luego encontramos el archivo de instantánea del montón hprof, que se puede cargar y analizar a través de la herramienta jvisualvm.Ahora
inserte la descripción de la imagen aquí
el archivo de instantánea, el tipo de archivo debe ser seleccionado como una instantánea del montón
inserte la descripción de la imagen aquí
Después de cargar, puede ver directamente el mensaje de error de desbordamiento de memoria
inserte la descripción de la imagen aquí
Después de hacer clic en el nombre del hilo principal, puede ubicar directamente la ubicación de desbordamiento de memoria
inserte la descripción de la imagen aquí

jstat: monitorear la información de la máquina virtual

jstat -gc pid 500 10: pid es el ID del subproceso e imprime el estado del montón de Java cada 500 milisegundos (capacidad, capacidad de uso, tiempo gc, etc. de cada área). Imprimiendo 10 veces jstat también puede monitorear el tamaño de la memoria de cada área y monitorear la clase cargando información desde otros ángulos
inserte la descripción de la imagen aquí
Específicamente, puede buscar en Google el uso detallado de jstat. La siguiente es la comparación de resultados.

S0C: el tamaño de la primera área superviviente
S1C: el tamaño de la segunda zona superviviente
S0U: el tamaño utilizado de la primera zona superviviente
S1U: el tamaño utilizado de la segunda zona superviviente
EC: el tamaño del área Eden
EU: el uso del área de Edén Tamaño
OC: Tamaño de generación anterior
OU: Tamaño de uso de generación anterior
MC: Tamaño de área de método
MU: Tamaño de uso de área de método
CCSC: Tamaño de espacio de clase comprimido CCSU
: Tamaño de uso de espacio de clase comprimido
YGC: Tiempos de recolección de basura de generación joven
YGCT: Jóvenes Tiempo de consumo de recolección de basura de generación
FGC: tiempos de recolección de basura de generación anterior
FGCT: tiempo de recolección de basura de generación anterior
GCT: tiempo total de recolección de basura
Unidad: KB

jinfo: ver los parámetros del proceso

jinfo (Información de configuración para Java) Verifica los parámetros de configuración de la máquina virtual y también se puede usar para ajustar los parámetros de configuración de la máquina virtual.

En muchos casos, las aplicaciones Java no especifican todos los parámetros de la máquina virtual Java. En este momento, es posible que los desarrolladores no conozcan el valor predeterminado de un parámetro de máquina virtual Java específico. En este caso, puede ser necesario obtener el valor predeterminado de un parámetro consultando la documentación. Este proceso de búsqueda puede ser muy difícil. Pero con la herramienta jinfo, los desarrolladores pueden encontrar fácilmente el valor actual de los parámetros de la máquina virtual Java.

jinfo no solo puede ver el valor real de un determinado parámetro de la máquina virtual Java en tiempo de ejecución, sino que incluso puede modificar algunos parámetros en tiempo de ejecución y hacer que surta efecto inmediatamente. Sin embargo, no todos los parámetros admiten la modificación dinámica. Los parámetros solo se pueden modificar en tiempo real con la bandera marcada como manejable. De hecho, esta capacidad de modificación es extremadamente limitada.
inserte la descripción de la imagen aquí

Indicadores de VM:
Indicadores de VM no predeterminados: -XX:CICompilerCount=12 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=null -XX:InitialHeapSize=2097152 -XX:MaxHeapSize=209715200 -XX:MaxNewSize=69730304 -XX:MinHeapDeltaBytes=52 4288 -Xx: OldSize = 524288 -xx:+useCompisEdClassPoInters -xx:+useCompisEdops -xx:+UseFastUnorderedtimeMeSeStamps -xx: -useLarGepagesIndIntualAlocation -xx:+UseParallElgc de
comando: -xms2m -xmx200m -xx:+HealApDumponOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOUTOOTOUTOUTOUTOUT PPATH = D: \ -javaagent:D:\Archivos de programa\JetBrains\IntelliJ IDEA 2022.2.1\lib\idea_rt.jar=54817:D:\Archivos de programa\JetBrains\IntelliJ IDEA 2022.2.1\bin -Dfile.encoding=UTF-8

A través de jinfo -flags pid: Ver el valor del parámetro al que se le ha asignado un valor

inserte la descripción de la imagen aquí
jinfo no solo puede ver el valor real de un determinado parámetro de la máquina virtual Java en tiempo de ejecución, sino que incluso puede modificar algunos parámetros en tiempo de ejecución y hacer que surta efecto inmediatamente. Sin embargo, no todos los parámetros admiten la modificación dinámica. Los parámetros solo se pueden modificar en tiempo real con la bandera marcada como manejable. Puede usar el comando manejable java -XX:+PrintFlagsInitial | grep para ver el
inserte la descripción de la imagen aquí
formato de modificación manejable de la siguiente manera:

  • Para modificación de tipo booleano: jinfo -flag ±parameter pid
  • Para tipos no booleanos: jinfo -flag nombre del parámetro = valor del parámetro pid

Por ejemplo, modifique e imprima la demostración del registro de GC de la siguiente manera: jinfo -flag +PrintGCDetails PID

//查看进程
C:\Users\Administrator>jps -l
20924 org.example.Main
...

//查看是否设置PrintGCDetails参数配置
C:\Users\Administrator>jinfo -flag PrintGCDetails 20924

//增加jvm参数:打印GC详情
C:\Users\Administrator>jinfo -flag +PrintGCDetails 20924

//查看是否设置PrintGCDetails参数配置
C:\Users\Administrator>jinfo -flag PrintGCDetails 20924
-XX:+PrintGCDetails
...

Resolver el problema de CPU100% en línea

En general, el 100 % de la CPU se debe básicamente a un bucle infinito de código. La idea central de la investigación es encontrar el servidor correspondiente, ubicar qué códigos en qué subproceso de qué proceso causó el problema e introducir brevemente los ejemplos de códigos anormales en ese momento.

El primer paso es encontrar el proceso que consume la mayor cantidad de CPU: use top -c para ver el proceso y luego ingrese la gran P para ordenar según el uso de la CPU.
inserte la descripción de la imagen aquí
El segundo paso es encontrar el subproceso que consume la mayor cantidad de CPU en el proceso: busque el proceso con la CPU más alta, encuentre el ID del proceso (PID), encuentre el subproceso correspondiente a este proceso a través del comando top -Hp PID, y luego ingrese la gran P para ordenar según el uso de la CPU.
inserte la descripción de la imagen aquí
Obtener el primer PID es el ID de subproceso que consume más tiempo, y luego usar printf "%x\n" PID para convertir el PID de decimal a hexadecimal (la razón para convertir a hexadecimal es porque en la pila, la identificación del subproceso se expresa en hexadecimal).

[root@VM-4-2-centos ~]# printf "%x\n" 13759
35bf

A continuación, necesitamos usar jstack para imprimir la información de la pila del proceso y luego usar grep para ver las cosas relacionadas con el subproceso correspondiente. ID de proceso jstack | grep "ID de subproceso" -C5 --color

jstack 30979  | grep "35bf" -C5 --color

En este momento, puede imprimir el código y luego hacer coincidir el nid de la instantánea del subproceso impreso, puede ubicar qué subproceso requiere mucho tiempo y, al mismo tiempo, ubicar rápidamente el código, puede ver qué método en qué clase causó la CPU el 100% de la razón.
inserte la descripción de la imagen aquí

Monitoreo remoto

Si no está muy familiarizado con los comandos, es una molestia usar comandos para monitorear la JVM.JVisualvm proporciona la función remota jmx. El valor predeterminado es proporcionar servicios RMI a través de la dirección IP de localhost, lo que requiere que configuremos los parámetros de JVM de forma remota para habilitar las conexiones remotas.

-Xms256m 
-Xmx512m 
-Xss256m 
-XX:PermSize=512m 
-XX:MaxPermSize=1024m 

-Dcom.sun.management.jmxremote 
-Djava.rmi.server.hostname=服务器IP 
#远程服务的端口:
-Dcom.sun.management.jmxremote.port=9015 
#客户端 rmi通信端口
-Dcom.sun.management.jmxremote.rmi.port=9015 
#关闭ssl功能
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 

Luego agregamos el host remoto en el Jvisualvm local
inserte la descripción de la imagen aquí
y luego agregamos la conexión remota jmx
inserte la descripción de la imagen aquí
para establecer los parámetros de conexión remota y cancelar la conexión SSL. ss
El artículo ha terminado. Si le es útil, haga una buena revisión. Su aliento es mi mayor motivación

Supongo que te gusta

Origin blog.csdn.net/u014494148/article/details/130657041
Recomendado
Clasificación