Análisis de fugas de memoria JVM (el más completo de la historia)

El artículo es muy extenso, se recomienda recopilarlo y leerlo despacio! Observaciones: Actualización continua ...

Libros y materiales clásicos necesarios para ingresar a una gran fábrica, mejorar la estructura y obtener un salario alto:


Recomendación 2: Lista general de preguntas de la entrevista para los reclutas de primavera de 2021 con un salario mensual de más de 50,000

Obtenga las siguientes preguntas de la entrevista, el salario mensual de los reclutas de primavera de 2021 es más de 50,000 (¡fuerte!) Ali, Jingdong, Meituan, Toutiao ... ¡Elige y camina de lado a voluntad! ! !
Conceptos básicos de Java
1: Preguntas de la entrevista JVM (la más fuerte de la historia, actualización continua, recomendación de hematemesis) https://www.cnblogs.com/crazymakercircle/p/14365820.html
2: Preguntas de la entrevista básica de Java (la más completa de la historia, actualización continua, recomendación de hematemesis) https://www.cnblogs.com/crazymakercircle/p/14366081.html
3: Preguntas de la entrevista de interbloqueo (las más sólidas de la historia, actualizadas continuamente) [https://www.cnblogs.com/crazymakercircle/p/14323919.html]
4: Preguntas de entrevista de patrón de diseño (la más completa de la historia, actualización continua, recomendación de hematemesis) https://www.cnblogs.com/crazymakercircle/p/14367101.html
5: Preguntas de la entrevista de diseño de arquitectura (la más completa de la historia, actualización continua, recomendación de hematemesis) https://www.cnblogs.com/crazymakercircle/p/14367907.html
También hay más de 10 preguntas de la entrevista que deben cepillarse y cepillarse Para obtener más información ..., consulte el 【Catálogo de alta concurrencia de Crazy Maker Circle

Recomendación 3: serie de alta concurrencia SpringCloud de Crazy Maker Circle

Publicaciones de blog de alta calidad de springCloud
combate real nacos (el mas completo de la historia) centinela (el tutorial introductorio más completo de la historia)
springcloud + webflux combate de alta concurrencia Webflux (el más completo de la historia)
Gateway SpringCloud (el más completo de la historia)
Hay más de 10 artículos que se cepillarán, el cepillo será de Bowen de alta calidad Para obtener más información ..., consulte el 【Catálogo de alta concurrencia de Crazy Maker Circle

Preguntas de la entrevista de optimización del rendimiento de JVM

Problemas comunes del área de memoria JVM

¿Hay una fuga de memoria en Java, brevemente?

¿Asignación de memoria Java?

¿Cuál es la estructura del montón de Java?

¿Qué es el espacio de Perm Gen en el montón?

¿Describe brevemente los cambios en el área de memoria de cada versión?

¿Hablar del papel de cada área?

Problemas comunes del subsistema de ejecución de JVM

¿Proceso de carga de clases de Java?

Describir el principio y el mecanismo de carga de archivos de clase de JVM ¿Qué es un cargador de clases?

¿Qué son los cargadores de clases?

¿El mecanismo del modelo de delegación de padres del cargador de clases?

Preguntas frecuentes sobre la recolección de basura

¿Qué es GC?

¿Por qué hay una GC?

¿Describe brevemente el mecanismo de recolección de basura de Java?

¿Cómo juzgar si un objeto está vivo?

¿Las ventajas y principios de la recolección de basura y considerar 2 tipos de mecanismos de reciclaje?

¿Cuál es el principio básico del recolector de basura?

¿Puede el recolector de basura recuperar memoria inmediatamente?

¿Hay alguna forma de notificar proactivamente a la máquina virtual para la recolección de basura?

¿Copia profunda y copia superficial?

¿Qué harán System.gc () y Runtime.gc ()?

Si la referencia del objeto se establece en nula, ¿el recolector de basura liberará inmediatamente la memoria ocupada por el objeto?

¿Qué es la recolección de basura distribuida (DGC)?

¿Como funciona?

¿Cuál es la diferencia entre un colector en serie y un colector de rendimiento?

En Java, ¿cuándo se puede recolectar la basura de un objeto? Describa brevemente GC menor y GC mayor ¿Se producirá la recolección de basura en la generación permanente de la JVM? ¿Cuáles son los métodos de recolección de basura en Java?

Problemas comunes de optimización del rendimiento

Cuénteme sobre la evaluación de desempeño y los indicadores de prueba que comprende.

¿Cuáles son los métodos de optimización del rendimiento más utilizados?

¿Qué es el ajuste de GC?

Herramienta de ajuste de JVM

Jconsole, jProfile, VisualVM

Jconsole: jdk viene con él, con funciones simples, pero se puede usar cuando el sistema tiene cierta carga. Hay un seguimiento muy detallado del algoritmo de recolección de basura. Para obtener más información, consulte aquí.

JProfiler : software comercial, es necesario pagar. Poderoso. Para obtener más información, consulte aquí.

VisualVM : viene con JDK, potente, similar a JProfiler. recomendar.

Un estudio preliminar de JVisualVM

VisualVM es el subproyecto de perfil de Netbeans, que se incluye en la actualización 7 de JDK6.0 (no se requieren parámetros específicos cuando se inicia java, la herramienta de monitoreo está en bin / jvisualvm.exe), que puede monitorear subprocesos, condiciones de memoria, y ver el tiempo de CPU del método Y los objetos en la memoria, los objetos que han sido GC, la vista inversa de la pila asignada (por ejemplo, qué objetos son asignados por 100 objetos String).

Debajo de JDK_HOME / bin (C: \ Archivos de programa \ Java \ jdk1.6.0_13 \ bin de forma predeterminada), hay un archivo jvisualvm.exe. Haga doble clic para abrirlo. Desde la interfaz de usuario, este software se desarrolla en base a NetBeans.

Puede realizar monitorización remota y local. El monitoreo remoto necesita abrir jmx, que se mencionará a continuación.

Su página predeterminada es:

img

El lado izquierdo se divide en local y remoto. Haga doble clic en el hilo de VisualVM en el local, puede ver el siguiente contenido de monitoreo:

img

Para una introducción específica, consulte:

http://www.ibm.com/developerworks/cn/java/j-lo-visualvm/

VisualVM puede instalar diferentes complementos según las necesidades. Cada complemento tiene un enfoque diferente. Algunos monitorean principalmente GC, algunos principalmente monitorean la memoria y algunos monitorean subprocesos.
Inserte la descripción de la imagen aquí
cómo instalar:

1. Seleccione "Herramientas"> "Complementos" en el menú principal. 2. En la pestaña "Complementos disponibles", seleccione la casilla de verificación "Instalar" del complemento. Haga clic en "Instalar". 3. Complete el procedimiento de instalación del complemento paso a paso.

Aquí tomo Eclipse (pid 22296) como ejemplo. Haga doble clic en él y expanda directamente. La interfaz principal muestra los dos contenidos principales del sistema y jvm. Haga clic en los parámetros de jvm y las propiedades del sistema en la parte inferior derecha para consultar la información detallada información de parámetros.
Inserte la descripción de la imagen aquí
Debido a que hay demasiados complementos para VisualVM, presentaré principalmente tres aquí. Utilizo principalmente algunos: monitoreo, subprocesos y
monitoreo de Visual GC . La página de inicio de monitoreo son en realidad los gráficos de cpu, memoria, clase , y subproceso.
Inserte la descripción de la imagen aquí
No hay mucha diferencia entre las funciones subproceso y jconsole.
Inserte la descripción de la imagen aquí
Visual GC es uno que se utiliza a menudo. Función, puede ver claramente los cambios de memoria de la generación joven y la generación anterior, así como la frecuencia gc y tiempo de GC.
Inserte la descripción de la imagen aquí
Las funciones anteriores casi también están disponibles en jconsole. VisualVM es más completo e intuitivo. Además, hay muchas otras funciones de VisualVM, que pueden analizar volcar instantáneas de memoria,
volcar instantáneas de subprocesos y analizarlas, y hay muchos otros complementos ins puedes explorar
Inserte la descripción de la imagen aquí

Combate real

Prepárese para simular la demostración de pérdida de memoria

1. Defina la variable estática HashMap

2. Cree objetos en segmentos y agréguelos a HashMap

El código es el siguiente:

import java.util.HashMap;
import java.util.Map;
public class CyclicDependencies {
    //声明缓存对象
    private static final Map map = new HashMap();
    public static void main(String args[]){
        try {
            Thread.sleep(10000);//给打开visualvm时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //循环添加对象到缓存
        for(int i=0; i<1000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("first");
        //为dump出堆提供时间
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<1000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("second");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<3000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("third");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for(int i=0; i<4000000;i++){
            TestMemory t = new TestMemory();
            map.put("key"+i,t);
        }
        System.out.println("forth");
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("qqqq");
    }
}

3. Configure los parámetros de jvm de la siguiente manera:

         -Xms512m
         -Xmx512m
         -XX:-UseGCOverheadLimit
         -XX:MaxPermSize=50m

4. Ejecute el programa y abra la supervisión de visualvm.

JVisualVM supervisa Tomcat de forma remota

1. Modifique el archivo de configuración catalina.sh de tomcat remoto y agregue:

  • JAVA_OPTS = "$ JAVA_OPTS
  • Djava.rmi.server.hostname = 192.168.122.128
  • Dcom.sun.management.jmxremote.port = 18999
  • Dcom.sun.management.jmxremote.ssl = falso
  • Dcom.sun.management.jmxremote.authenticate = false "

Esta vez, la configuración no pasa por la verificación de permisos. Simplemente abra el puerto jmx.

2. Abra jvisualvm, haga clic con el botón derecho en remoto y seleccione agregar host remoto:
Inserte la descripción de la imagen aquí

3. Ingrese el nombre del host y escriba ip directamente, de la siguiente manera:
Inserte la descripción de la imagen aquí
Haga clic con el botón derecho en el host recién creado, seleccione Agregar conexión JMX e ingrese el puerto configurado en tomcat.

4. Haga doble clic para abrir. ¡completo!

Utilice JVisualVM para analizar las pérdidas de memoria

1. Verifique la pestaña Visual GC. El contenido es el siguiente. Esta es una captura de pantalla de la salida primero.
Inserte la descripción de la imagen aquí
Esta es una captura de pantalla de la salida de la cuarta:
Inserte la descripción de la imagen aquí
A través de la comparación de dos imágenes , se encuentra que la
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
generación anterior ha estado en gc.Cuando el programa continúa ejecutándose, se puede encontrar que la generación anterior gc aún continúa:
Inserte la descripción de la imagen aquí
aumentar es 7 veces, pero la memoria de la generación anterior no ha disminuido. Muestra que hay objetos que no se pueden reciclar, puede ser una pérdida de memoria.
¿Cómo analizar que se filtre el objeto? Abra la pestaña del muestreador: haga clic como se muestra en la figura siguiente:
Inserte la descripción de la imagen aquí
siga la salida del programa para volcar el montón, cuando se genere en segundo lugar, volcar una vez, cuando se genere más tarde, volcar una vez.
Ingrese la etiqueta del montón del último volcado, haga clic en la categoría:
Inserte la descripción de la imagen aquí
haga clic en la esquina superior derecha: "Comparar con otro almacenamiento dinámico". Como se muestra en la figura, seleccione la primera comparación de contenido de volcado de exportación: Los
Inserte la descripción de la imagen aquí
resultados de la comparación son los siguientes: Se
Inserte la descripción de la imagen aquí
puede ver que la instancia del objeto TestMemory ha ido aumentando y más en el intervalo entre los dos tiempos, lo que indica que el método al que hace referencia el El objeto puede tener una pérdida de memoria.
¿Cómo ver la relación de referencia del objeto?
Haga clic con el botón derecho en la clase TestMemory y seleccione "Mostrar en la vista de instancia", como se muestra a continuación: el
Inserte la descripción de la imagen aquí
lado izquierdo es el número total de instancias creadas, el lado superior derecho es la estructura de la instancia, la siguiente es una descripción de referencia, como se puede ser visto en la figura de la clase CyclicDependencies. HashMap hace referencia y hace referencia a él.

De esta manera, se puede determinar la ubicación de la fuga, y luego analizarla y resolverla de acuerdo con la situación real.

Cómo realizar el ajuste de JVM

Observar la liberación de memoria, inspección de clases de colección, árbol de objetos

Todas las herramientas de ajuste anteriores proporcionan funciones potentes, pero en general se dividen en las siguientes categorías de funciones

Vista de información de montón

img

Puede ver la asignación de espacio de pila (generación joven, generación anterior, asignación de generación persistente)

Proporcionar recolección de basura instantánea

Monitoreo de basura (monitoreando la situación del reciclaje durante mucho tiempo)

img

Ver la información de clase y objeto en el montón. Ver: cantidad, tipo, etc.

img

Vista de referencia de objeto

Con la función de ver la información del montón, generalmente podemos resolver los siguientes problemas sin problemas:

-¿Es razonable la división por tamaño de las generaciones jóvenes y viejas?

--Pérdida de memoria

-Si la configuración del algoritmo de recolección de basura es razonable

Monitoreo de subprocesos

img

Monitoreo de información de subprocesos: el número de subprocesos del sistema.

Monitoreo del estado del hilo: en qué estado se encuentra cada hilo

img

Detalles del hilo de volcado: ver el funcionamiento interno del hilo

Verificación de interbloqueo

Análisis de puntos calientes

img

CPU caliente : compruebe el sistema qué método requiere mucho tiempo de CPU

Puntos calientes de memoria : el número máximo de comprobaciones de qué objetos (los objetos sobreviven un cierto tiempo, las estadísticas y la destrucción de objetos juntos) en el sistema.

Estas dos cosas son muy útiles para la optimización del sistema. Podemos buscar el cuello de botella del sistema y optimizar el sistema de manera específica en función de los puntos de acceso encontrados, en lugar de optimizar sin rumbo fijo todos los códigos.

Instantánea

Una instantánea es un fotograma congelado del sistema que se ejecuta en un momento determinado. Cuando estamos sintonizando, es imposible rastrear todos los cambios del sistema con nuestros ojos. Al confiar en la función de instantánea, podemos hacer la diferencia entre los objetos (o clases, subprocesos, etc.) en dos tiempos de ejecución diferentes del sistema en orden para encontrar el problema rápidamente

Por ejemplo, quiero comprobar si se ha perdido algún objeto que debería recuperarse después de que el sistema haya sido recolectado como basura. Luego, puedo tomar una instantánea de la situación del montón antes y después de la recolección de basura, y luego comparar la situación del objeto de las dos instantáneas.

Verificación de fugas de memoria

La fuga de memoria es un problema relativamente común y la solución también es relativamente general, aquí podemos enfocarnos en él, mientras que el hilo y los temas candentes son problemas específicos que se analizan en detalle.

Las fugas de memoria generalmente se pueden entender como recursos del sistema (recursos en todos los aspectos, montón, pila, subprocesos, etc.) en el caso de un uso incorrecto, lo que da como resultado que los recursos utilizados no se puedan reciclar (o no reciclar), dando lugar al nuevo recurso. La solicitud de asignación no se puede completar, lo que provoca un error del sistema.

La pérdida de memoria es más dañina para el sistema, ya que puede provocar que el sistema se bloquee directamente.

Es necesario distinguir, existe una diferencia entre la pérdida de memoria y la sobrecarga del sistema, aunque el resultado final puede ser el mismo. La pérdida de memoria es que los recursos gastados no se recuperan y provocan errores, mientras que la sobrecarga del sistema es que el sistema no tiene tantos recursos para asignar (hay otros recursos en uso).

El espacio del montón de la vieja generación está lleno

异常 : java.lang.OutOfMemoryError: espacio de almacenamiento dinámico de Java

Descripción:

img

Este es el método de pérdida de memoria más típico. En pocas palabras, todo el espacio del montón está lleno de objetos basura que no se pueden reciclar y la máquina virtual ya no puede asignar espacio nuevo.

Como se muestra en la figura anterior, esta es una imagen de recolección de basura muy típica de una fuga de memoria. Todas las partes máximas son puntos de recolección de basura y todas las partes inferiores representan la memoria restante después de una recolección de basura. Conectando todos los puntos del valle, puede encontrar una línea de abajo hacia arriba, que muestra que con el paso del tiempo, el espacio del montón del sistema se ocupa continuamente y, finalmente, se ocupará todo el espacio del montón. Por lo tanto, se puede considerar de manera preliminar que puede haber una pérdida de memoria en el sistema. (La imagen de arriba es solo un ejemplo; en situaciones reales, la recopilación de datos lleva más tiempo, como varias horas o días)

resolver:

Este método también es relativamente fácil de resolver. Generalmente, se basa en la comparación de la situación antes y después de la recolección de basura, y el análisis basado en la situación de referencia del objeto (referencia de objeto de recolección común), y básicamente se puede encontrar la fuga.

La generación persistente está ocupada

** 异常 : ** java.lang.OutOfMemoryError: espacio PermGen

Descripción:

El espacio de la permanente está ocupado. Una excepción causada por la imposibilidad de asignar espacio de almacenamiento para una nueva clase. Esta excepción no existía antes, pero es más común hoy en día cuando la reflexión de Java se usa mucho. La razón principal es que una gran cantidad de clases generadas por reflexión dinámica se cargan constantemente, lo que eventualmente hace que el área de Perm se llene.

Aún más aterrador es que incluso si diferentes classLoaders usan la misma clase, todos la cargarán, lo que equivale a lo mismo.Si hay N classLoaders, se cargará N veces. Por lo tanto, en algunos casos, este problema se considera básicamente irresoluble. Por supuesto, no hay muchos casos en los que haya un gran número de classLoaders y un gran número de clases de reflexión.

resolver:

  1. -XX: MaxPermSize = 16m

  2. Cambie a JDK. Como JRocket.

Desbordamiento de pila

** Excepción: ** java.lang.StackOverflowError

** Nota: ** No diré mucho sobre esto, generalmente se debe a que la recursividad no regresa o llamadas cíclicas

Pila de subprocesos llena

异常: Fatal: tamaño de pila demasiado pequeño

Nota : El tamaño del espacio de un hilo en Java es limitado. Después de JDK5.0, este valor es 1M. Los datos relacionados con este hilo se almacenarán en él. Pero cuando el espacio de subprocesos está lleno, se producirá la excepción anterior.

Solución : aumente el tamaño de la pila de hilos. -Xss2m. Pero esta configuración no puede resolver el problema fundamental y depende de si hay una fuga en la parte del código.

La memoria del sistema está llena

异常: java.lang.OutOfMemoryError: no se puede crear un nuevo hilo nativo

Descripción :

Esta excepción se debe a que el sistema operativo no tiene suficientes recursos para generar este hilo. Cuando el sistema crea subprocesos, además de asignar memoria en el montón de Java, el propio sistema operativo también necesita asignar recursos para crear subprocesos. Por lo tanto, cuando el número de subprocesos alcanza un cierto nivel, puede haber espacio en el montón, pero el sistema operativo no puede asignar recursos y se produce esta excepción.

Cuanta más memoria se asigna a la máquina virtual Java, menos recursos quedan en el sistema. Por lo tanto, cuando la memoria del sistema es fija, cuanta más memoria se asigna a la máquina virtual Java, menos subprocesos puede generar el sistema. La relación es inversamente proporcional . Al mismo tiempo, puede reducir el espacio asignado a un solo subproceso modificando -Xss, y también puede aumentar el número total de subprocesos producidos en el sistema.

resolver:

  1. Rediseñe el sistema para reducir el número de subprocesos.

  2. Si no se puede reducir el número de subprocesos, utilice -Xss para reducir el tamaño de un solo subproceso. Para poder producir más hilos.

Sugerencias de optimización de parámetros de JVM

Básicamente, reduce la cantidad de GC.

Si se trata de una aplicación que crea objetos con frecuencia, puede aumentar adecuadamente el tamaño de la generación joven. Más constantes pueden aumentar el tamaño de la generación persistente. Para objetos con más singleton, se puede aumentar el tamaño de la generación anterior. Por ejemplo, en aplicaciones de primavera.

Selección de GC, después de JDK5.0, JVM juzgará de acuerdo con la configuración actual del sistema . Generalmente, ejecute el comando -Server. gc incluye tres estrategias: serial, paralelo y concurrente.

El rendimiento se aplica en gran medida. En general, se utiliza la recopilación en paralelo y se activan varios subprocesos para acelerar el gc.

Las aplicaciones con alta velocidad de respuesta generalmente utilizan la recopilación simultánea, como los servidores de aplicaciones.

Se recomienda configurar la generación anterior como un recolector concurrente. Dado que el recolector concurrente no comprime ni desfragmenta los discos, se recomienda configurar:

-XX: + UseConcMarkSweepGC # Recolecta al mismo tiempo la vieja generación

-XX: CMSInitiatingOccupancyFraction = 80 # Indica que el CMS se ejecutará cuando el espacio de la generación anterior alcance el 80%

-XX: + UseCMSCompactAtFullCollection # Activa la compresión para la generación anterior. Puede afectar el rendimiento, pero puede eliminar la fragmentación de la memoria.

-XX: CMSFullGCsBeforeCompaction = 10 # Dado que el recopilador concurrente no comprime ni organiza el espacio de memoria, producirá "fragmentos" después de ejecutarse durante un período de tiempo, lo que reducirá la eficiencia operativa. Este parámetro está configurado para comprimir y organizar el espacio de la memoria después de ejecutar FullGC.

Supongo que te gusta

Origin blog.csdn.net/crazymakercircle/article/details/113758988
Recomendado
Clasificación