Pila de área de datos de tiempo de ejecución de JVM (memoria de pila)

Área-montón de datos en tiempo de ejecución

El concepto central del montón

La descripción del montón de Java en la "Especificación de la máquina virtual de Java" es: todas las instancias de objetos y matrices deben asignarse al montón en tiempo de ejecución. (El montón es el área de datos en tiempo de ejecución desde la que se asigna la memoria para todas las instancias de clase y matrices).

Pero desde una perspectiva práctica, "casi" todas las instancias de objetos asignan memoria aquí. Debido a que todavía hay algunos objetos asignados en la pila, y es posible que las matrices y los objetos nunca se almacenen en la pila, debido a que el marco de la pila guarda una referencia, esta referencia apunta a la ubicación del objeto o matriz en la pila.

  • El montón es exclusivo de un proceso de JVM, es decir, un proceso corresponde a una instancia de JVM, pero el proceso contiene varios subprocesos y comparten el mismo espacio de montón;
  • Solo hay una memoria de pila para una instancia de JVM y la pila es el área central de la gestión de memoria de Java;
  • El área de almacenamiento dinámico de Java se crea cuando se inicia la JVM, se determina su tamaño y es el espacio de memoria más grande gestionado por la JVM;
  • Pero el tamaño de la memoria dinámica se puede ajustar;
  • La "Especificación de la máquina virtual de Java" estipula que el montón puede estar en un espacio de memoria físicamente discontinuo, pero lógicamente debe considerarse como continuo (comparable a un sistema operativo);
  • El montón de Java se puede dividir en búferes privados de subprocesos (búfer de asignación local de subprocesos, TLAB), lo que significa que no toda la información del montón es compartida por subprocesos.

El siguiente código explica la memoria dinámica:

public class HeapDemo {
    
    
    public static void main(String[] args) {
    
    
        System.out.println("start...");
        try {
    
    
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }

        System.out.println("end...");
    }
}

Establecer el tamaño del montón:

-Xms10m: memoria de pila mínima
-Xmx10m: memoria de pila máxima
Inserte la descripción de la imagen aquí

La siguiente figura muestra el uso de Java VisualVM para ver el contenido del espacio del montón a través del complemento GC en VisualVM.
Inserte la descripción de la imagen aquí

Una vez finalizado el método, los objetos del montón no se eliminarán de inmediato, solo se eliminarán durante la recolección de basura, es decir, cuando se active el GC, se recopilarán.

Porque si los objetos del montón se reclaman inmediatamente, el hilo del usuario se verá afectado.

La conexión entre el montón, la pila de Java y el área de métodos:
Inserte la descripción de la imagen aquí
desglose de la memoria del montón

La memoria de pila de Java 7 y versiones anteriores está lógicamente dividida en tres partes: área de recién nacidos + área de cuidados para personas mayores + área permanente:

  • Young Generation Space Young / New se divide en el área de Edén y el área de Supervivientes;
  • Espacio de generación de tenencia Antiguo / Tenencia;
  • Permanente Espacio Perm.

La memoria de pila de Java 8 y posteriores se divide lógicamente en tres partes: Área de pensión del área de recién nacidos + espacio meta:

  • Young / New in Young Generation Space se divide en el área Eden y el área Survivor;
  • Espacio de generación de tenencia Antiguo / Tenencia;
  • Meta Space Meta.

Convención: Área de recién nacidos -> Nueva generación -> Generación joven, área de cuidado de personas mayores -> Área de ancianos -> Generación anterior, área permanente -> Generación permanente La
Inserte la descripción de la imagen aquí
estructura interna del espacio de almacenamiento, antes de JDK1.8, reemplaza la generación permanente por el meta espacio! ! !
Inserte la descripción de la imagen aquí
El espacio montón incluye lógicamente el Cenozoico, la Vieja Generación y el Metaspacio, pero en realidad solo incluye el Cenozoico y la Vieja Generación. ¡El Metaspacio también se llama Área de Método! ! !

Establecer el tamaño de la memoria del montón y OOM

El área de almacenamiento dinámico de Java se utiliza para almacenar instancias de objetos Java, por lo que el tamaño de almacenamiento dinámico ya está establecido cuando se inicia la JVM y se puede establecer con las opciones "-Xmx" y "-Xms".

  • "-Xms" se utiliza para indicar la memoria inicial del área del montón, que es equivalente a -xx: InitialHeapSize;
  • "-Xmx" se usa para indicar la memoria máxima del área del montón, que es equivalente a -XX: MaxHeapSize.
  • Una vez que el tamaño de la memoria en el área del montón exceda la memoria máxima especificada por "-xmx", se lanzará una excepción outofMemoryError.
  • Por lo general, los dos parámetros -Xms y -Xmx se configuran con el mismo valor. El propósito es poder calcular el tamaño del área del montón sin volver a calcular el área del montón después de que el mecanismo de recolección de basura de Java haya limpiado el área del montón, mejorando así el rendimiento.

por defecto:

  1. Tamaño de la memoria inicial: tamaño de la memoria física de la computadora / 64;
  2. Tamaño máximo de la memoria: tamaño de la memoria física de la computadora / 4.

La siguiente prueba de código para ver el tamaño de la memoria del montón:

public class HeapSpaceInitial {
    
    
    public static void main(String[] args) {
    
    

        //返回Java虚拟机中的堆内存总量
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        //返回Java虚拟机试图使用的最大堆内存量
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;

        System.out.println("-Xms : " + initialMemory + "M");
        System.out.println("-Xmx : " + maxMemory + "M");

        //System.out.println("系统内存大小为:" + initialMemory * 64.0 / 1024 + "G");
        //System.out.println("系统内存大小为:" + maxMemory * 4.0 / 1024 + "G");

        try {
    
    
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }
}

Resultado de salida

-Xms : 246M
-Xmx : 3934M

Cómo ver la asignación de memoria de la memoria dinámica:

jps  ->  jstat -gc 进程id

Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Ejemplo de OutOfMemory

Ejemplo de código:

public class OOMTest {
    
    
    public static void main(String[] args) {
    
    
        ArrayList<Picture> list = new ArrayList<>();
        while(true){
    
    
            try {
    
    
                Thread.sleep(20);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            list.add(new Picture(new Random().nextInt(1024 * 1024)));
        }
    }
}

class Picture{
    
    
    private byte[] pixels;

    public Picture(int length) {
    
    
        this.pixels = new byte[length];
    }
}

Establecer parámetros de inicio

-Xms500m -Xmx:500m
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at com.heu.heap.OOMTest.main(OOMTest.java:21)

Vea el uso de memoria específico a través de la herramienta VisualVM:

Inserte la descripción de la imagen aquí
Se puede ver que cuando el montón usado llega a 500, se producirá una excepción OOM.

Joven y viejo

Los objetos Java almacenados en la JVM se pueden dividir en dos categorías:

  • Un tipo son los objetos instantáneos con un ciclo de vida corto. Este tipo de objeto se crea y muere muy rápidamente. Si el ciclo de vida es corto, se puede reciclar a tiempo;
  • El ciclo de vida de otro tipo de objeto es muy largo y, en algunos casos extremos, aún puede ser coherente con el ciclo de vida de la JVM.

Si el área del montón de Java se subdivide aún más, se puede dividir en generación joven (YoungGen) y generación anterior (oldGen).

Entre ellos, la generación joven se puede dividir en espacio Edén, espacio Survivor0 y espacio Survivor1 (a veces llamado de área y a área).
Inserte la descripción de la imagen aquí
Los siguientes parámetros del montón generalmente no se ajustan durante el desarrollo:
Inserte la descripción de la imagen aquí

  • Eden : De : a -> 8: 1: 1
  • La nueva generación: la vieja generación -> 1: 2

Configure la proporción de la generación joven y la generación anterior en la estructura del montón:

  • El valor predeterminado -XX: NewRatio = 2 significa que la nueva generación representa 1, la generación anterior representa 2 y la nueva generación representa 1/3 de todo el montón;
  • Puede modificar -XX: NewRatio = 4, lo que significa que la nueva generación ocupa 1, la generación anterior ocupa 4 y la nueva generación ocupa 1/5 de todo el montón;
  • Cuando se descubre que hay demasiados objetos con un ciclo de vida largo en todo el proyecto, puede ajustar el tamaño de la generación anterior para realizar ajustes;
  • En la máquina virtual HotSpot, la proporción predeterminada del espacio de Eden y los otros dos espacios de supervivientes es 8: 1: 1. Por supuesto, los desarrolladores pueden ajustar esta proporción de espacio a través de la opción "-xx: SurvivorRatio". Por ejemplo -xx: SurvivorRatio = 8.

Casi todos los objetos Java son nuevos en el área del Edén y la mayoría (80%) de los objetos Java se destruyen en la nueva generación (algunos objetos grandes irán directamente a la generación anterior cuando no se puedan almacenar en el área del Edén).

Puede utilizar la opción "-Xmn" para establecer el tamaño máximo de memoria de la nueva generación.
Y este parámetro generalmente usa el valor predeterminado.
Inserte la descripción de la imagen aquí

Supongo que te gusta

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