El diagrama de estructura de memoria JVM más simple

Diagrama de estructura de la memoria JVM


image.png

Hola a todos. No he actualizado durante varios días. El contenido de hoy es demasiado. Vamos a presentar el diagrama de estructura interna de JVM en detalle. Es el mismo que antes. El caso es el primero , para que todos puedan entender y recuerda.

/ ** 
 * @author : jiaolian 
 * @date : Creado en 2021-03-10 21:28 
 * @description: helloworld test jvm memory area 
 * @modified By: 
 * Official account : Calling 
 * / 
public class HelloWorldTest { 

    public static void main (String [] args) { 
        // Crea un nuevo objeto HelloWorldTest; 
        HelloWorldTest helloWorldTest = new HelloWorldTest (); 
        // Crea dos nuevos hilos para llamar a sayHello 
        para (int i = 0; i <2; i ++) { 
            new Thread ( () -> helloWorldTest.sayHello ("mundo")). start (); 
        } 
    } 

    / ** 
     * Saluda a alguien 
     * @param who 
     * /  
    public void sayHello (String who) {
        System.out.println (Thread.currentThread (). getName () + "¡hola!" + quién);
    } 
}

El código anterior: crea dos nuevos subprocesos en el bucle for en el subproceso principal para llamar a sayHello, y los dos últimos subprocesos respectivamente saludan al mundo. Este código es más fácil de entender, por lo que no se publicará el resultado de salida. Escribimos y ejecutamos este código, principalmente miramos cómo funciona este código en la JVM.

Primero, escribimos un archivo HelloWorldTest.Java, que se convertirá en código de bytes HelloWorldTest.class después de la compilación javac . ¿Por qué debería convertirse en código de bytes? ¡Porque la máquina virtual Java puede reconocerlo! Finalmente, el código de bytes es cargado en la memoria por el subsistema de carga de clases ClassLoader. Cada bloque de memoria tiene su propia función y, finalmente, el motor de ejecución ejecuta el código de bytes. ¡A continuación nos centramos en el papel que juega cada bloque de memoria!

image.png


Área de métodos


El área de método contiene principalmente información estática, como metadatos de clase, grupo constante, información de método, variables de clase, etc. El código anterior HelloWorldTest.class son metadatos de clase, sayHello, main son información del método, etc. se almacenan en el área de métodos. También hay dos puntos a tener en cuenta en el área de métodos:

  1. Si el área del método es demasiado grande y excede la configuración, se informará un error de espacio OutOfMemoryError: PermGen. La herramienta gclib puede generar clases dinámicamente para probar el error.
  2. Antes de JDK1.7, el área de método se llamaba generación permanente y después de 1.8 se llamaba metaspace . La razón es que para liberar la presión de la administración, JDK1.8 entregó el grupo de constantes en tiempo de ejecución al montón para su administración.


montón


El montón almacena principalmente objetos de instancia. Puede entenderlo de esta manera, siempre que vea el objeto con la palabra clave new , los datos se colocan en el montón. El código anterior es HelloWorldTest helloWorldTest = new HelloWorldTest (); helloWorldTest es una referencia al objeto HelloWorldTest, que apunta a la nueva instancia del objeto HelloWorldTest. La referencia helloWorldTest se coloca en la pila, también llamada variable local ( el tipo de objeto declarado en el método o el tipo ordinario), simplemente dibujamos una imagen para mostrar la relación entre el siguiente montón, pila y área de método . Cuando la JVM ejecuta HelloWorldTest helloWorldTest = new HelloWorldTest (); en esta oración, la estructura de memoria de la JVM se ve así. Si la referencia al objeto desaparece, el GC reciclará el objeto.

image.png

En la memoria acumulada, la memoria debe dividirse en dos áreas, la generación joven y la generación anterior. Como se muestra abajo.

  1. Cenozoico: En la memoria acumulada, el Cenozoico se divide en tres partes, eden (Eden crea una nueva vida, correspondiente al nuevo objeto), desde, hasta, estas tres áreas de memoria pertenecen al Cenozoico, la proporción predeterminada es 8: 1 : 1, cada nuevo objeto se almacenará primero en eden, si la memoria del área de eden está llena, activará el monitor gc para reclamar el área, los objetos que no han sido recuperados se colocarán en el desde o hacia, desde, a la memoria, uno de los cuales está vacío, conveniente Los objetos se ordenan y marcan en la memoria. Cada vez que se recolecta un objeto, desde y hacia se mueven, la edad del objeto no recuperado también aumenta en 1. Cuando alcanza un cierto edad (el valor predeterminado es 15 años ), ingresará la vejez.
  2. Vejez: cuando la vejez esté completa, se activará la recuperación completa de GC. Si el sistema es demasiado grande, la GC completa no podrá recuperarse. El programa tendrá un aspecto similar a java.lang.OutOfMemoryError: Java heap space. Nosotros puede configurar parámetros de JVM: como -Xmx32m Establezca la memoria de pila máxima en 32M.

La razón para particionar el montón es facilitar que la JVM maneje automáticamente la recolección de basura . La memoria de pila es el área principal recopilada por GC .

image.png



Apilar


El espacio de memoria de la pila es relativamente pequeño en comparación con el espacio del montón, y también es privado para el subproceso. La pila es principalmente un marco de pila, que es el primero en entrar y el último en salir. Se entiende que el marco de la pila corresponde a un método. El método contiene variables locales, parámetros de método y métodos. Exportar, acceder al puntero constante y la tabla de información de excepciones. La tabla de información de excepciones y la información del puntero constante pueden no estar visibles en el cuerpo del método, pero pueden reflejarse en el class a través de la herramienta Jclasslib tool class, y se puede procesar la tabla de información de excepciones.Cuando el programa ejecuta un error, saltará a la línea de código específica para ejecutar, y la JVM se retroalimenta a través de la tabla de excepciones. Todavía combinamos ejemplos y diagramas para analizar en detalle. Cuando el programa se está ejecutando, la pila en la JVM puede aparecer como se muestra en la siguiente figura.

image.png    

Un subproceso puede corresponder a varios marcos de pila. Los marcos de pila se insertan de arriba a abajo, primero en último, como se muestra en la siguiente figura, llaman al método B en el método A, llaman a C en el método B y llaman al método en el método. C D, el hilo principal corresponde a la situación de apilado del marco de la pila, la secuencia de apilado es D-> C -> B -> A, y el programa final finaliza. También tenga en cuenta: La pila de operandos significa almacenar los resultados intermedios de los cálculos de variables locales. Por ejemplo, int x = 1 se define en el método A; las variables locales se colocan en la pila de operandos para cálculos posteriores en la JVM. La pila también tiene un tamaño de espacio. Si la pila es demasiado grande y excede la profundidad de la pila, se informará un error similar, java.lang.OutOfMemoryError: Java stack space. El ejemplo más común es la recursividad. ¿Escribirás ejemplos recursivos de prueba de demostración?


image.png


Contador de programa


El contador de programa también es exclusivo de los subprocesos. La ejecución de programas con subprocesos múltiples depende de la ejecución del segmento de tiempo de asignación de la CPU . Dibuje un diagrama simple para ver cómo el subproceso múltiple utiliza los segmentos de tiempo de la CPU. Como se muestra en la siguiente figura, el hilo 0 y el hilo 1 asignan porciones de tiempo de la CPU para ejecutar el programa de forma alternativa. Suponiendo que el hilo 0 obtiene primero la porción de tiempo, la CPU asignará la porción de tiempo al hilo 1 nuevamente después de que se agote la porción de tiempo. Después de que se ejecuta el hilo 1, esto Cuando el segmento de tiempo vuelve al hilo 0 para ejecutarse, entonces la pregunta es, ¿ dónde se ejecutó el hilo 0 la última vez? ¿Cuántas líneas de código hay? ¿Se ha ejecutado esa línea de código? En este momento, entra en juego el contador de programa , y el contador de programa guarda la escena de ejecución del hilo, lo que facilita la siguiente reanudación de la operación. Es por eso que el contador del programa es exclusivo de los hilos.

image.png



Pila de métodos nativos


La pila de métodos nativos no se introducirá demasiado, como la estructura de pila, es un área independiente, pero corresponde al método nativo.


Memoria directa


La memoria directa es independiente de la memoria que no sea la memoria JVM y puede interactuar directamente con la interfaz NIO. La interfaz NIO operará con frecuencia la memoria. Si se coloca en la administración de JVM, sin duda aumentará la sobrecarga de JVM. Por lo tanto, esta pieza se propone por separado, y los datos son manipulados directamente por la memoria Comparado con JVM, es más rápido y obviamente mejora el rendimiento del programa.



Optimización del rendimiento de la asignación de memoria-análisis de escape


Dijimos antes que mientras veamos la palabra clave new, el objeto debe estar asignado en el montón . Veamos un caso.

/ ** 
 * @author : jiaolian 
 * @date : Creado en 2021-03-10 16:10 
 * @description: Prueba de análisis de escape 
 * @modificado por: 
 * Número público: 叫 练
 * / 
public class EscapeTest { 

    // privado estático Objeto objeto; 
    public static void alloc () { 
        // Un objeto tiene un tamaño equivalente a 16k, no un objeto de escape 
        // object = new Object (); 
        Object object = new Object (); 
    } 

    public static void main (String [ ] args) throws InterruptedException { 
        // Millones de veces la memoria 
        long begin = System.currentTimeMillis (); 
        for (int i = 0; i <10000000; i ++) { 
            alloc (); 
        } 
        long end = System.currentTimeMillis ();
        System.out.println ("tiempo:" + (fin-comienzo)); 
    } 
}

Como en el código anterior, usamos el bucle for 100 millones de veces para un nuevo objeto en la función principal. Un objeto es 16k. Se estima aproximadamente que hay datos de GB. En este momento, configuramos manualmente los parámetros de JVM, -XX : + PrintGC -Xmx10M -XX: + DoEscapeAnalysis; configurado para imprimir información de GC, la memoria de pila máxima predeterminada es 10M.

  1. -XX: + ImprimirGC . Indica que la consola imprime información del GC.
  2. -Xmx10M . Establezca la memoria de pila máxima en 10M.
  3. -XX: + DoEscapeAnalysis . Habilite el análisis de escape ( habilitado de forma predeterminada ).

Ejecute el programa y el resultado de la impresión se muestra en la siguiente figura. Se han realizado un total de 3 GC, ¿puede tener alguna pregunta ? La memoria de pila de 10M necesita adaptarse al impacto de los datos de GB. ¿Por qué requiere N GC, por qué solo 3 GC? Si -XX: - Análisis de escape cercano de DoEscapeAnalysis, la GC puede ocurrir miles de veces. El tiempo de ejecución también ha aumentado de 3 milisegundos a más de 1000 milisegundos. Muestra que los objetos que no son de escape no se compilan en el montón recién construido, sino que se compilan en la pila . Los beneficios de hacerlo: Desde el punto de vista del número de ejecuciones y el tiempo de ejecución del programa GC, se mejora la eficiencia de la operación del programa.

image.png

  • Análisis de causa:

Observe el método alloc () en el código de caso anterior. Object object = new Object () en el método; el objeto es una variable local. Después de cada nueva creación, se creará en el siguiente ciclo. El último objeto creado se mostrará fuera de la pila y el objeto al que se hace referencia. El objeto puntiagudo dejará de ser válido y el GC lo reclamará. Una vez que se activa el análisis de escape, los objetos creados por new Object () no se asignan en el montón, sino que se colocan en la pila. Así es como la JVM optimiza la memoria a través del análisis de escape. Pensando en ello, si suelta el objeto Objeto estático privado; comente, ¿seguirá siendo el objeto un objeto que no escapa?

Nota: ¡Los objetos de escape no pueden asignar espacio en la pila!

Creo que a estas alturas debería tener una comprensión más clara del análisis de escape .


para resumir


De acuerdo, estoy un poco cansado de escribir. Estoy incompleto y todavía hay muchas cosas que deben corregirse. Espero que puedas corregir y comentar. Si quieres, dale me gusta y presta atención. Punto de atención, no te pierdas, me llamaron número público [de práctica ] , la Micro Señal [jiaolian123abc] les decía mientras practicaba.

image.png


Supongo que te gusta

Origin blog.51cto.com/14883474/2656420
Recomendado
Clasificación