Montón de área de datos en tiempo de ejecución de JVM (proceso de asignación de objetos)

Proceso de asignación de objetos de montón

concepto

Asignar memoria para nuevos objetos es una tarea muy rigurosa y complicada. Los diseñadores de JVM no solo deben considerar cómo y dónde asignar la memoria, sino también porque el algoritmo de asignación de memoria está estrechamente relacionado con el algoritmo de recuperación de memoria, por lo que también debe considerar GC Si se generará fragmentación de memoria en el espacio de memoria después de que se realice la recuperación de memoria.

Se explican los siguientes puntos:

  • El nuevo objeto se coloca primero en Eden Park, esta área tiene un límite de tamaño;
  • Cuando el espacio en el Jardín del Edén se llena, el programa necesita crear objetos nuevamente. El recolector de basura de la JVM realiza una recolección de basura (MinorGC) en el Jardín del Edén, destruye los objetos en el Jardín del Edén que ya no están referenciado por otros objetos, y luego carga otros nuevos Coloque el sujeto en el Eden Park;
  • Luego, mueva los objetos restantes en el Jardín del Edén a la Zona de Supervivientes 0;
  • Si la recolección de basura se activa nuevamente, los que sobrevivieron la última vez se colocarán en el área del sobreviviente 0, si no se recolectan, se colocarán en el área del sobreviviente 1 (el área 0 y el área 1 se intercambian entre sí);
  • Si vuelve a pasar por la recolección de basura, se volverá a colocar en el área del sobreviviente 0 en este momento y luego irá al área del sobreviviente 1.
  • ¿Cuándo puedo ir al área de retiro? Puede establecer el número de veces. El valor predeterminado es 15 veces;
  • En el área de retiro, es relativamente tranquilo. Cuando la memoria del área de vejez es insuficiente, GC se activa nuevamente: GC principal para limpiar la memoria del área de vejez;
  • Si después de ejecutar Major GC en el área de cuidado de ancianos, se encuentra que el objeto aún no se puede guardar, se producirá una excepción OOM.

El parámetro (número de veces) se puede configurar: -Xx: MaxTenuringThreshold = N para configurar.

Proceso grafico

  1. Los objetos que creamos generalmente se almacenan en el área del Edén. Cuando el área del Edén está llena, se activará la operación GC, que generalmente se denomina operación YGC / Minor GC;
    Inserte la descripción de la imagen aquí

  2. Cuando realicemos una recolección de basura, las rojas se reciclarán, y las verdes se ocuparán y almacenarán en el área S0 (Survivor From). Al mismo tiempo, se establece un contador de edad para cada objeto, que es 1 después de una colección;

  3. Al mismo tiempo, el área del Edén continúa almacenando objetos. Cuando el área del Edén esté llena nuevamente, se activará una operación de MinorGC. En este momento, el GC recolectará los objetos en Eden y Survivor From una vez, y colocará los objetos supervivientes en el área Survivor A. Al mismo tiempo, deje age + 1;
    Inserte la descripción de la imagen aquí

  4. Seguimos realizando generación de objetos y recolección de basura. Cuando la edad del objeto en Survivor llegue a los 15, se disparará una operación de promoción, es decir, el objeto en la generación joven será promovido a la generación vieja; cuando el
    Inserte la descripción de la imagen aquí
    área de supervivencia sea ¿completo?

  • Preste especial atención a que MinorGC solo se activará cuando el área de Edén esté llena, y la operación de MinorGC no se activará cuando el área de supervivientes esté llena;
  • Si el área de Superviviente está llena, se activarán algunas reglas especiales, es decir, se puede promover directamente a la generación anterior.

Ejemplo: Tomando a los militares como ejemplo, la promoción de una persona normal puede ser: reclutar -> líder de escuadrón -> líder de pelotón -> comandante de compañía.

Pero también es posible que algunas personas hayan hecho una gran contribución directamente de los reclutas -> líder de pelotón.

El código de caso especial
Inserte la descripción de la imagen aquí
de asignación de objetos demuestra el proceso de asignación de objetos.

Programa de muestra: cree constantemente objetos grandes y agréguelos a la lista:

public class HeapInstanceTest {
    
    
    byte [] buffer = new byte[new Random().nextInt(1024 * 200)];
    public static void main(String[] args) throws InterruptedException {
    
    
        ArrayList<HeapInstanceTest> list = new ArrayList<>();
        while (true) {
    
    
            list.add(new HeapInstanceTest());
            Thread.sleep(10);
        }
    }
}

Luego configure los parámetros de JVM:

-Xms600m -Xmx600m

Inserte la descripción de la imagen aquí
Luego, abra la herramienta VisualVM y ejecute el código anterior para ver dinámicamente a través de VisualGC:
Inserte la descripción de la imagen aquí
Finalmente, cuando la generación anterior y la nueva están llenas, aparece OOM.

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.heu.heap.HeapInstanceTest.<init>(HeapInstanceTest.java:13)
	at com.heu.heap.HeapInstanceTest.main(HeapInstanceTest.java:17)

para resumir

  • Resumen para el área de supervivientes s0, s1: hay intercambio después de copiar, y quien está vacío es para (s0, s1 no son fijos);
  • En cuanto a la recolección de basura: se recolecta frecuentemente en el área de recién nacidos, rara vez se recolecta en la generación anterior y casi no se recolecta en la generación permanente y el metaespacio;
  • El propósito de la nueva generación de algoritmos de replicación: reducir la fragmentación interna.

GC menor, GC mayor, GC completo

  • Minor GC: la nueva generación de GC

  • Major GC: GC de la vejez

  • GC completo: colección de montón completa, recolección de basura que recopila todo el área de métodos y montón de Java

  • Todos sabemos que una parte del ajuste de JVM es la recolección de basura. Necesitamos evitar la recolección de basura tanto como sea posible, porque en el proceso de recolección de basura, los problemas STW (detener la palabra) son propensos a ocurrir, y la GC mayor y la GC completa El tiempo de aparición de STW es más de 10 veces mayor que el de Minor GC.

  • Cuando JVM está realizando GC, no siempre recupera las tres áreas de memoria anteriores juntas.La mayoría de las veces, la recuperación se refiere a la nueva generación. Para la implementación de Hotspot VM, el GC en él se divide en dos tipos según el área de recuperación: uno es recolección parcial (GC parcial) y el otro es recolección completa (FullGC).

Recolección parcial: la recolección de basura no es una colección completa de todo el montón de Java. Que se divide en:

  • La recolección de la generación joven (MinorGC / YoungGC): solo la generación joven de la recolección de basura.
  • Recolección de vieja generación (MajorGC / o1dGC): solo recolección de basura en la vieja generación.
    -Actualmente, solo CMSGC tiene el comportamiento de recopilar generaciones antiguas por separado; -Tenga
    en cuenta que en muchos casos Major GC se confundirá con Full GC, y es necesario distinguir específicamente si se trata de una colección de generaciones anteriores o una colección de montón completa.
  • Recolección mixta (MixedGC): Recolecte la recolección de basura de toda la generación joven y parte de la generación anterior.
    -Actualmente, solo G1 GC tendrá este comportamiento.

Colección de almacenamiento dinámico completo (FullGC): recopile la recolección de elementos no utilizados de todo el área de métodos y almacenamiento dinámico de Java.

GC menor

  • Cuando el espacio de la generación joven es insuficiente, MinorGC se activará. La generación joven completa aquí se refiere a la generación Edén completa, y el Survivor completo no activará un GC (cada vez que el Minor GC limpiará la memoria de la generación joven) ;
  • Debido a que la mayoría de los objetos Java tienen la función de desactivación nocturna de Chaosheng , Minor GC con mucha frecuencia recupera una velocidad relativamente rápida;
  • Minor GC activará STW (detiene la palabra), suspenderá los hilos de otros usuarios y esperará hasta que termine la recolección de basura antes de que los hilos del usuario se reanuden.
    Inserte la descripción de la imagen aquí

Mayor GC

Majoy GC se refiere al GC que ocurrió en la vejez, cuando el objeto desaparece de la vejez, se dice que ha ocurrido "Major Gc" o "Full GC".

  • La aparición de Major GC suele ir acompañada de al menos un Minor GC (pero no absoluto, hay un proceso directo de selección de la estrategia Major GC en la estrategia de recopilación del colector Paralle1 Scavenge), es decir, cuando el espacio de la generación anterior es insuficiente, intentará activar Minor GC primero. Si no hay suficiente espacio después, se activará un GC mayor;
  • La velocidad de Major GC es generalmente más de 10 veces más lenta que la de MinorGc, y el tiempo de STW es más largo. Si la memoria no es suficiente después de Major GC, se informará como OOM.

GC completo

Hay cinco situaciones que desencadenan la ejecución de Full GC:

  1. Al llamar a System.gc (), el sistema recomienda ejecutar Full GC, pero no necesariamente se ejecuta;
  2. Espacio insuficiente en la vejez;
  3. Espacio insuficiente en el área de métodos;
  4. El tamaño medio de la generación anterior después de pasar el GC menor es mayor que la memoria disponible de la generación anterior;
  5. Al copiar desde el área de Edén y el área de espacio de superviviente (Desde el espacio) al área de espacio de superviviente (Al espacio), si el tamaño del objeto es mayor que la memoria disponible del Espacio al espacio, el objeto se transferirá al antiguo edad, y la memoria disponible de la vejez es menor que el tamaño del objeto (es decir, el tamaño de la memoria de la generación joven y la generación anterior no se ajusta al objeto).

Nota: La GC completa debe evitarse tanto como sea posible durante el desarrollo o el ajuste. De esta forma el tiempo temporal será más corto.

Ejemplo de GC

Escriba una excepción OOM, creando constantemente ejemplos de cadenas:

public class GCTest {
    
    
    public static void main(String[] args) {
    
    
        int i = 0;
        try {
    
    
            List<String> list = new ArrayList<>();
            String a = "mogu blog";
            while(true) {
    
    
                list.add(a);
                a = a + a;
                i++;
            }
        }catch (Exception e) {
    
    
            e.getStackTrace();
        }
    }
}

Establezca los parámetros de inicio de la JVM:

-Xms10m -Xmx10m -XX:+PrintGCDetails

Registro impreso:

[GC (Allocation Failure) [PSYoungGen: 2038K->500K(2560K)] 2038K->797K(9728K), 0.3532002 secs] [Times: user=0.01 sys=0.00, real=0.36 secs] 
[GC (Allocation Failure) [PSYoungGen: 2108K->480K(2560K)] 2405K->1565K(9728K), 0.0014069 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2288K->0K(2560K)] [ParOldGen: 6845K->5281K(7168K)] 9133K->5281K(9728K), [Metaspace: 3482K->3482K(1056768K)], 0.0058675 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] 5281K->5281K(9728K), 0.0002857 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(2560K)] [ParOldGen: 5281K->5263K(7168K)] 5281K->5263K(9728K), [Metaspace: 3482K->3482K(1056768K)], 0.0058564 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 2560K, used 60K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 2% used [0x00000000ffd00000,0x00000000ffd0f138,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 7168K, used 5263K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
  object space 7168K, 73% used [0x00000000ff600000,0x00000000ffb23cf0,0x00000000ffd00000)
 Metaspace       used 3514K, capacity 4498K, committed 4864K, reserved 1056768K
  class space    used 388K, capacity 390K, committed 512K, reserved 1048576K
  
  Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Arrays.java:3664)
	at java.lang.String.<init>(String.java:207)
	at java.lang.StringBuilder.toString(StringBuilder.java:407)
	at com.heu.heap.GCTest.main(GCTest.java:20)
[GC (Allocation Failure) [PSYoungGen: 2038K->500K(2560K)] 2038K->797K(9728K), 0.3532002 secs] 
  • [PSYoungGen: 2038K-> 500K (2560K)]: El espacio total de la generación joven es de 2560K, ocupando actualmente 2038K, y los 500K restantes después de la recolección de basura;
  • 2038K-> 797K (9728K): el espacio total de memoria del montón es 9728K, que actualmente ocupa 2038K, y quedan 797K después de la recolección de basura.

Cuando se activa el OOM, se debe realizar un GC completo, porque la excepción OOM solo se expondrá cuando el espacio en la generación anterior sea insuficiente.

Idea de generación de espacio de pila

¿Por qué dividir el montón de Java en generaciones? ¿No funciona correctamente independientemente de las generaciones?

Después de la investigación, los diferentes objetos tienen diferentes ciclos de vida. 70% -99% de los objetos son objetos temporales.

  • Cenozoico: Consiste en Edén y dos supervivientes del mismo tamaño (también llamado de / a o s0 / s1), y a siempre está vacío.
  • Generación anterior: almacene los objetos que sobrevivieron a muchos GC de la nueva generación.

De hecho, es completamente posible no dividir las generaciones, la única razón para las generaciones es optimizar el rendimiento del GC.

  • Si no hay generación, entonces todos los objetos están en el mismo lugar, es como encerrar a todas las personas de una escuela en un aula. Durante la GC, es necesario averiguar qué objetos son inútiles, de modo que se escaneen todas las áreas del montón. (Bajo rendimiento)
  • Muchos objetos viven y mueren. Si está generando generaciones, coloque el objeto recién creado en un lugar determinado. Cuando GC, primero reclame el área donde se almacenan los objetos "vivos y mueren", para que quede libre. Fuera mucho del espacio. (Más reciclaje de generaciones jóvenes y menos reciclaje de generaciones viejas mejorarán mucho el rendimiento)

Estrategia de asignación de memoria de objetos

  1. Si el objeto nació en el área del Edén y sobrevivió al primer CG menor y puede ser acomodado por Superviviente, se moverá al espacio Superviviente y la edad del objeto se establecerá en 1.
  2. Cada vez que un objeto sobrevive a un Minor GC en el área de Survivor, su edad aumenta en 1 año. Cuando su edad aumenta a un cierto nivel (el valor predeterminado es 15 años, de hecho, cada JVM y cada GC es diferente), ser promovido a la vejez.
  3. El umbral de edad para que el objeto sea promovido a la vejez se puede establecer mediante la opción ** - XX: MaxTenuringThreshold **.

Los principios de asignación de objetos para diferentes grupos de edad son los siguientes:

  1. Asignación de prioridad a Eden: las cadenas o matrices más largas en desarrollo existirán directamente en la vejez, pero debido a que los objetos recién creados son todo el día y la noche, este objeto grande también puede reciclarse pronto, pero es activado por la vejez Major GC tiene menos veces que Minor GC, por lo que puede ser más lento de recopilar.
  2. Los objetos grandes se asignan directamente a la generación anterior: intente evitar demasiados objetos grandes en el programa.
  3. Los objetos de larga duración se asignan a la generación anterior.
  4. Juicio dinámico de la edad de los objetos: si el tamaño total de todos los objetos de la misma edad en el área de Superviviente es mayor que la mitad del espacio de Superviviente, los objetos cuya edad sea mayor o igual a esta edad pueden ingresar directamente a la vejez sin esperar la edad requerida en MaxTenuringThreshold.
  5. Garantía de asignación de espacio: -XX: HandlePromotionFailure.

Supongo que te gusta

Origin blog.csdn.net/qq_33626996/article/details/113954578
Recomendado
Clasificación