JVM observa (1) área de memoria java y desbordamiento de memoria y creación, diseño y posicionamiento de objetos

Diagrama de arquitectura JVM

Inserte la descripción de la imagen aquí

1. Área del método

1. Es un área de memoria compartida entre hilos

2. Almacena información sobre la clase cargada por la máquina virtual (incluyendo tipo de clase, modificador, información del método e información de campo), variables estáticas de la clase, constantes de tipo final, campos en la clase, información de datos del método, constructor Y el contenido del código compilado por el compilador, etc.

Pero lo anterior es solo una especificación, y la implementación en diferentes máquinas virtuales es diferente.

Por ejemplo: List list=new ArrayList();List es la norma, ArrayList corresponde a diferentes implementaciones de diferentes máquinas virtuales.

Dos típico es el " perpetuos " (JDK8 antes) y " Yuan Espacio " (JDK8 y más allá)

Las variables de instancia se almacenan en el montón, independientemente del área del método.

Grupo constante de tiempo de ejecución

El grupo constante de tiempo de ejecución es parte del área de método. Se usa para almacenar varios literales y referencias de símbolos generados durante la compilación .

Como su nombre lo indica, las constantes generadas en tiempo de ejecución naturalmente se almacenarán aquí (dinámico).

Como el método intern () de String, si el grupo constante de cadenas ya contiene una cadena igual a este objeto String, se devolverá una referencia al objeto; de lo contrario, la cadena contenida en el objeto String se agregará al grupo constante.

Prueba:

 public static void main(String[] args) {
  
        String sb=new StringBuilder("哈哈").append("嘿嘿").toString();
        System.out.println(sb.intern()==sb);//true

        String sb2=new StringBuilder("ja").append("va").toString();
        //java在Version类中已经出现,字符串常量池已经有它的引用,因此返回false
        System.out.println(sb2.intern()==sb2);//false
    }

Como sigue:

package sun.misc;
public class Version {
    private static final String launcher_name = "java";
    private static final String java_version = "1.8.0_231";
    ..............................
}

Esta clase se carga en Bootstrap ClassLoader, ubicado en rt.jar \ sun \ misc:
Inserte la descripción de la imagen aquí

Situación anormal

Cuando el área de método no puede cumplir con los nuevos requisitos de asignación de memoria, se genera una excepción OOM.

Cuando el grupo constante de tiempo de ejecución no puede solicitar memoria, se generará una excepción OOM.

En segundo lugar, la pila

La pila es responsable de la ejecución (el montón es responsable del almacenamiento)

1. El hilo es privado y tiene el mismo ciclo de vida que el hilo , y no hay problema de recolección de basura

2. La ejecución de cada método crea un marco de pila y lo guarda en la parte superior de la pila. Cada método corresponde a un marco de pila de la pila a la pila desde la llamada hasta la ejecución.

Como sigue:

	public static void m1(){
        System.out.println("m1..begin");
        m2();
        System.out.println("m1..end");
    }
    public static void m2(){
        System.out.println("m2");
    }
    public static void main(String[] args) {
        System.out.println("main...begin");
        m1();
        System.out.println("main...end");

    }

El modelo de pila correspondiente es el siguiente:

El | El |

El | m2 () |

El | m1 () |

El | main () |

3. Los marcos de pila se utilizan para almacenar información como tablas de variables locales, pilas de operandos, conexiones dinámicas y salidas de métodos.

La información almacenada en la pila (o parte de la tabla de variables locales) es la siguiente:

8 tipos básicos de variables + variables de referencia de objeto + métodos de instancia

Tabla de variables locales : almacene variables locales en el método (variables no estáticas declaradas en el método, parámetros de entrada y salida, etc.). 8 tipos básicos de variables almacenan directamente los valores correspondientes, y las variables de referencia del objeto almacenan un puntero de referencia a la dirección inicial del objeto, o a un controlador que representa el objeto u otra ubicación relacionada con el objeto)

Referencia al grupo constante de tiempo de ejecución : cuando usamos constantes en una clase en un método, necesitamos una referencia al grupo constante de tiempo de ejecución.

Pila de operandos : registra todas las operaciones de apilamiento y apilamiento relacionadas con el cálculo en el método

Salida del método : una vez que finaliza el método, necesitamos saber desde dónde se llamó antes, por lo que debemos guardar la dirección devuelta por un método.

Excepciones relacionadas con la pila

1. El tamaño de la pila solicitada por el subproceso es mayor que el tamaño permitido por la máquina virtual, y se producirá un error StackOverflowError.

2. Se produce una excepción OOM cuando la expansión dinámica de la aplicación de pila no puede obtener suficiente memoria. (La máquina virtual HotSpot actual no se puede expandir dinámicamente, por lo que después de que un subproceso se aplique correctamente para el espacio de pila, no habrá una excepción OOM, pero OOM seguirá ocurriendo si la aplicación falla)

Prueba de excepción de pila:

Para el primer caso, puede reducir el tamaño de la pila:

Aparece StackOverflowError

public class VMStackSOF {
    private static int stackLength = 0;

    //-Xss150k 减少栈内存容量 StackOverFlow
    public void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        VMStackSOF oom=new VMStackSOF();
       try {
            oom.stackLeak();
        }catch (Throwable e){
            System.out.println("栈长度:"+oom.stackLength);
            throw e;
        }

    }
}

O cambie la tabla de variables locales del marco del método para que sea demasiado grande:

public class VMStackSOF {
    private static int stackLength = 0;

    //增大方法帧中本地变量表的长度 StackOverFlowError
    public static void test() {
        long a1,.......a100;//100个局部变量
        stackLength++;
        test();
        a1 =a2=.....a100;
    }

    public static void main(String[] args) {
        VMStackSOF oom=new VMStackSOF();
 
       try {
           test();
       }catch (Error a){
           System.out.println("长度"+stackLength);
            throw a;
       }


    }
}

Tres, montón

1. Para compartir entre subprocesos, creados cuando se inicia la máquina virtual

2. Se usa para almacenar instancias de objetos y matrices

3. El área de memoria administrada por el recolector de basura, también conocido como el "montón GC".

Sin embargo, debe tenerse en cuenta que con el desarrollo de la tecnología de compilación, especialmente la tecnología de análisis de escape se está volviendo más poderosa, también se puede realizar la asignación en pila y TLAB.

Se puede ampliar aquí:

Sobre la asignación en la pila:

Hay muchos objetos que no escapan al método, y si se crean en el montón, cuando se llama al método, el ciclo de vida del objeto finaliza y la referencia al objeto en el montón en consecuencia Sin él, el GC recuperará el objeto. Si hay muchos de esos objetos, la presión sobre el GC aumentará.

En este momento, podemos dispersar dichos atributos de objeto y asignarlos en la pila, de modo que después de que se complete la llamada al método, el reciclaje del espacio de la pila reciclará los objetos dispersos. Esto evita agregar presión al GC y mejora el rendimiento.

Sobre TLAB:

Debido a que el montón es un área de memoria compartida globalmente, y la creación de objetos es un comportamiento muy frecuente, por lo que se deben sincronizar varios subprocesos al asignar memoria a los objetos simultáneamente (jvm usa el método de reintento de falla CAS para garantizar la atomicidad), Y esta sobrecarga es muy grande en algunos casos.

El TLAB (Thread Local Allocation Buffer) es para dividir el buffer de asignación privada de múltiples hilos en el montón, de modo que cuando el hilo asigna el espacio del montón, primero se asigna a su propio buffer para evitar la sobrecarga causada por la sincronización para mejorar el objeto Eficiencia de distribución. (Jvm está activado de forma predeterminada, también puede usar la -XX: +UseTLABpantalla para activarlo), pero cuando el objeto es demasiado grande, todavía asigna espacio directamente en el montón.

Use el -XX:+PrintTLABparámetro para activar el seguimiento del uso de TLAB,

Use -XX:TLABSizeeste parámetro para especificar el tamaño del espacio TLAB asignado a cada subproceso

Composición del espacio del montón

El montón está compuesto por la generación anterior y la generación joven, y la generación joven se divide en el área del Edén y las dos áreas de sobrevivientes (desde el espacio hasta el espacio).

El objeto se asigna primero al área eden de la generación joven, pero si el objeto es más grande que el área eden y más pequeño que el área anterior, se arroja directamente al área antigua.Si es más grande que la generación anterior, se produce una excepción OOM.

En el área de sobrevivientes, los objetos siguen vivos después de que muchos GC se transfirieron al área de ancianos.

Configuración de tamaño de montón

El valor mínimo -Xms y el valor máximo -Xmx controlan el tamaño del montón.

Cuando -Xms y -Xmx son iguales, el montón es de tamaño fijo y no se puede expandir automáticamente; de ​​lo contrario, se puede expandir automáticamente

Anormal

Cuando la memoria en el montón no es suficiente para asignar espacio de objetos y el montón no se puede expandir, se genera una excepción OOM.

Prueba de anomalía

Use los dos parámetros anteriores para controlar el tamaño de XX:+HeapDumpOnOutOfMemoryErroralmacenamiento dinámico a 10 MB, y agregue el parámetro para volcar la instantánea de volcado de almacenamiento dinámico de memoria actual cuando aparezca OOM.

public class HeapOOM {
    static class OOM{

    }

    /**
     * -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
     * -XX:+HeapDumpOnOutOfMemoryError 让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照
     * @param args
     */
    public static void main(String[] args) {
        /*
            java.lang.OutOfMemoryError: Java heap space
            Dumping heap to java_pid9368.hprof ...
            Heap dump file created [28275886 bytes in 0.140 secs]
         */
        List<OOM> list=new ArrayList<>();
        while (true){
            list.add(new OOM());
        }
    }
}

Usamos el complemento integrado IDEA jprofiler para ejecutar, abrir la instantánea de volcado del montón obtenida, puede encontrar rápidamente la ubicación anormal.

Inserte la descripción de la imagen aquí

Cuarto, el contador del programa

Puede considerarse como el indicador de número de línea del código de bytes ejecutado por el bloqueo de hilo actual.El intérprete de códigos de bytes funciona cambiando el valor de este contador para seleccionar la siguiente instrucción de código de bytes que se ejecutará.

Dado que varios subprocesos en la máquina virtual java se implementan mediante el cambio de subprocesos y la asignación del tiempo de ejecución del procesador, en cualquier momento, un procesador solo ejecutará instrucciones en un subproceso.

Por lo tanto, para restaurar la posición de ejecución antes de cambiar después de cambiar los subprocesos , cada subproceso debe tener un contador de programa independiente, que no interfiera entre sí y se almacene de forma independiente.

Por lo tanto, el contador del programa es privado para el hilo.

Si se ejecuta un método java, se registra la dirección de instrucción del código de bytes de la máquina virtual que se está ejecutando.

Si se ejecuta el método nativo local, el valor del contador no está definido.

Sin excepción OOM

Cinco, pila de métodos locales

Básicamente es lo mismo que la pila de Java, pero la pila de métodos locales es compatible con los métodos nativos locales, y la pila es para los métodos de Java.

La excepción ocurre de la misma manera que la pila.

Seis, la creación de objetos.

Aquí solo se analizan los objetos Java comunes, excluyendo las matrices y los objetos de clase.

Cuando la máquina virtual encuentra una nueva instrucción:

1. nueva instrucción

Compruebe si el parámetro de este comando puede estar en el conjunto de constantes para apuntar a una clase de referencias simbólicas si, y para comprobar la clase representada por el símbolo de referencia se ha cargado, analizada e inicializado. De lo contrario, el proceso de carga de clase correspondiente debe realizarse primero .

2. Asignar memoria

El tamaño de memoria requerido del objeto se puede determinar completamente después de que se complete la inicialización de la clase.

Hay dos formas de asignar memoria:

a. Colisión del puntero (Bump The Pointer)

Cuando la memoria de almacenamiento dinámico es regular, un lado se usa memoria y el otro es memoria libre. Se usa un puntero como indicador en el medio. La asignación es mover el puntero al lado libre en la misma distancia que el tamaño del objeto.

b. Lista libre (Lista libre)

Cuando la memoria de almacenamiento dinámico no es regular, la máquina virtual mantiene una lista que registra qué bloques de memoria están disponibles. La asignación de memoria es encontrar un espacio lo suficientemente grande de la lista para asignar a la instancia del objeto y actualizar el contenido de la lista.

El método de asignación se determina si el montón es regular, y si el montón es regular, se determina si el recolector de basura puede realizar la compresión y clasificación del espacio.

3. Inicialización

Inicialice el espacio de memoria asignado (excluyendo el encabezado del objeto) a un valor de cero. (El método TLAB se puede llevar a cabo antes de la asignación de TLAB) para garantizar que el campo de instancia de objeto se pueda usar directamente sin asignar un valor inicial.

4. Configuración inicial del objeto.

Tales como: qué instancia del objeto , cómo encontrar la información de metadatos de la clase , el código hash del objeto , la edad de generación de GC, etc.

La información anterior almacenado en la cabecera del objeto (Object Header) en. Dependiendo del estado de ejecución actual de la máquina virtual, como si se debe habilitar el bloqueo de sesgo, etc., el encabezado del objeto tendrá diferentes configuraciones.

5. El método <init> ()

La nueva instrucción ejecutará el método init del archivo de clase, es decir, el constructor, para construir otros recursos e información de estado del objeto. Solo entonces es posible construir un objeto verdaderamente utilizable.

Siete, el diseño de memoria del objeto

En HotSpot, el diseño de almacenamiento de objetos en la memoria de almacenamiento dinámico se puede dividir en tres partes:

Encabezado de objeto (encabezado), datos de instancia (datos de instancia) y relleno de alineación (relleno)

7.1 Encabezado de objeto

Hay dos tipos principales de información:

  1. Se usa para almacenar los datos de tiempo de ejecución del objeto en sí

    Código hash, antigüedad de generación de GC, indicador de estado de bloqueo, bloqueo retenido por el subproceso, ID de subproceso sesgado, marca de tiempo sesgada.

  2. Puntero de tipo

    El objeto apunta a un puntero a sus metadatos de tipo, que determina qué instancia de clase es el objeto. (Pero la información de metadatos del objeto de búsqueda no tiene que pasar por el objeto en sí).

    Si el objeto es una matriz de Java, el encabezado del objeto también necesita registrar una longitud de la matriz.

7.2 Datos de ejemplo

Almacena información válida para objetos. Es decir, se registrará el contenido de varios tipos de campos definidos en el código (tanto los heredados por la clase principal como las subclases).

El orden de almacenamiento se ve afectado por el parámetro de estrategia de asignación de máquina virtual -XX: FieldsAllocationStyle y el orden de definición de campo.

El orden de asignación predeterminado es:

Longs / doubles, ints, short / chart, bytes / booleans, oops (punteros de objetos ordinarios), puede ver que los campos del mismo ancho siempre se asignan y almacenan juntos.

7.3 Alinear el relleno

El sistema automático de administración de memoria de la máquina virtual requiere que la dirección de inicio del objeto sea un múltiplo entero de 8 bytes, es decir, el tamaño del objeto debe ser un múltiplo entero de 8 bytes. Si los datos de la instancia no están alineados, deben rellenarse como un marcador de posición mediante un relleno de alineación. Completo

Ocho, posicionamiento de acceso a objetos

Java se refiere a objetos específicos en el montón a través de la referencia en la pila.

Hay dos formas principales: manejar y puntero directo

8.1 Acceso con asa

Una memoria se divide en el grupo de identificadores en el montón y la referencia almacena la dirección del identificador.

asa objeto contiene datos de instancia y tipo de datos de cada una de la información de dirección.

8.2 Puntero directo

La referencia almacena directamente la dirección del objeto . Si solo accede al objeto en sí, evita la sobrecarga de una visita al perfil.

Ventaja

Identificador : la referencia almacena la dirección del identificador estable. Cuando se mueve el objeto, el puntero de datos de instancia en el identificador de la enfermedad es inteligente.

Puntero directo : es más rápido y ahorra el tiempo de sobrecarga de posicionamiento del puntero. En el acceso frecuente a objetos Java, esta sobrecarga es muy considerable.

HotSpot utiliza principalmente punteros directos para el acceso a objetos.

================================================== ====================

Otras notas relacionadas:

Notas de JVM (2) La vida y muerte de los objetos y las cuatro principales referencias a Java

JVM observa (3) el algoritmo de recolección de basura y la implementación del algoritmo HotSpot (punto de seguridad, conjunto de memoria y tabla de tarjetas, barrera de escritura, marca de tres colores, etc.)

JVM señala "Cuatro" siete recolectores de basura comunes

JVM observa (cinco) mecanismo de carga de clases, cargador de clases y mecanismo de delegación principal

================================================== ==============

Referencia:
"Comprensión profunda de la tercera edición de la máquina virtual de Java"

Publicado 75 artículos originales · alabanza ganado 13 · vistas 8369

Supongo que te gusta

Origin blog.csdn.net/weixin_43696529/article/details/104884273
Recomendado
Clasificación