Comprender a fondo el proceso de JVM de principio a fin

¿Qué experimenta la JVM de principio a fin?

1. Cargar la Clase

Para una clase de Java, primero se compila en un archivo de clase. Cuando la máquina virtual ejecuta un método y encuentra que no hay una representación binaria de la clase en la memoria, intentará encontrar la representación binaria de la clase a través del cargador de clases .

Mecanismo de delegación de los padres

​ Dado el mismo nombre de clase, siempre se puede cargar en la misma clase. Esto se logra a través de la máquina de delegación principal. Cada cargador de clases tiene su propia estrategia de carga. HotSpot tiene varios cargadores de clases integrados. El directorio cuando se carga la clase cargado es diferente. Cuando el cargador de clases carga una clase, primero entregará la tarea de carga de la clase a su cargador de clases principal y delegará capa por capa. Si el cargador de clases principal puede cargarlo, entonces Cargando, si el cargador de clases principal la clase no se puede cargar, se entregará a la clase secundaria para que la cargue. Para decirlo sin rodeos, al cargar una clase, la prioridad del cargador de clases principal es mayor que la de la clase secundaria. Por ejemplo, si escribe un tipo String con el mismo nombre que el tipo String que viene con Java, entonces el programa definitivamente cargará el tipo String en la memoria cuando se inicie, y cargará el tipo String cuando se cargue la clase. La tarea se entrega a la clase principal. Para decirlo sin rodeos, es el cargador de clases que viene con Java. Él cargará su propio tipo de cadena en lugar de escribirlo usted mismo.

2. Enlace

Este proceso se puede dividir en tres pasos: verificación, preparación y análisis (opcional)

verificar

Este paso verifica que la clase cargada tenga el formato correcto, tenga una tabla de símbolos con el formato adecuado y tenga la semántica correcta.

Preparar

Los preparativos incluyen la asignación de espacio para el almacenamiento estático y las estructuras de datos utilizadas dentro de la máquina virtual.

Analizar (opcional)

​ El contenido principal de la fase de análisis es cargar otras clases e interfaces involucradas en la clase actual y verificar si la referencia es correcta. Este es un proceso recursivo, similar al enlace "estático" del lenguaje C. Por el contrario , también hay una forma de enlace más "perezosa": las clases o las interfaces solo se resuelven cuando se usan.

Los dos métodos anteriores tienen sus propias ventajas y desventajas. El primer método puede encontrar el problema antes de ejecutarse, mientras que el segundo método puede encontrarse en tiempo de ejecución.

3. Inicializar (iniciar)

La premisa de inicializar , lo cual es un proceso recursivo. El Objeto más simple es la superclase de todas las clases, por lo que esta inicialización recursiva termina con Objeto

Inicializar bloqueo

Debido a que Java tiene subprocesos múltiples, para evitar conflictos durante la carga, cada clase o interfaz tiene un bloqueo de inicialización único y tiene un estado para indicar la inicialización de esta clase. Hay un total de los siguientes: tipo:

  • Validado y listo, no inicializado
  • está siendo inicializado por un hilo
  • se ha inicializado y se puede utilizar
  • en estado de error, posiblemente la inicialización falló

Cuando un subproceso intenta inicializar una clase, primero adquirirá el bloqueo de inicialización y, después de adquirirlo, decidirá si liberar el bloqueo y esperar o no según su estado específico. Por ejemplo: esta clase está siendo inicializada por otro subproceso, luego el subproceso actual liberará el bloqueo de inicialización y entrará en el estado de bloqueo, hasta que se notifique al subproceso que se inicializa que la inicialización se ha completado.

4. Creación de nuevas instancias de clase

Instanciación explícita e instanciación implícita

Mostrar instanciación:

Esto es relativamente simple, de hecho, se instancia a través del constructor

Instanciación implícita:

1. Cargar una clase o interfaz que contenga un tipo String creará implícitamente un objeto String

2. Operaciones de boxeo, como el tipo de devolución Integer, pero al final del método return 0, se creará implícitamente una clase contenedora.

3. 字符串 + String类型La operación creará un nuevo objeto String

4. lambda表达式Se puede crear un objeto de instancia que implemente la interfaz .

proceso de creación de instancias

​ El constructor de la clase será llamado durante el proceso de creación de instancias. Hay cinco pasos en el proceso de procesamiento. Debido a que es más complicado, solo lo mencionaré brevemente aquí y luego dejaré que todos lo entiendan a través de ejemplos.

​ 1. Cuando se ejecuta el constructor, si el parámetro también es una clase, se ejecutará su constructor. Por ejemplo, si el parámetro es de tipo String, el constructor de String se ejecutará primero.

2. Antes de ejecutar la lógica específica en el constructor, primero se ejecutará el constructor de la clase principal. Este es un proceso recursivo, lo que significa que un super()constructor (excepto Object) está oculto.

3. Al llamar al constructor de la clase principal, al llamar a un método que está anulado por la subclase, se llamará primero a la subclase (a continuación se darán ejemplos)

Ejemplo 1:

class Point {
    
    
    // super(); //隐藏的父类构造方法
    int x, y;
    Point() {
    
     x = 1; y = 1; }
}
class ColoredPoint extends Point {
    
    
    // super(); //隐藏的父类构造方法
    int color = 0xFF00FF;
}
class Test {
    
    
    public static void main(String[] args) {
    
    
        ColoredPoint cp = new ColoredPoint();
        System.out.println(cp.color);
    }
}

Proceso de implementación

ColoredPoint() --> Point() --> Object() --> 初始化x,y --> Point() --> 初始化color变量

Ejemplo 2:

class Super {
    
    
    Super() {
    
     printThree(); }
    void printThree() {
    
     System.out.println("three"); }
}
class Test extends Super {
    
    
    int three = (int)Math.PI;  // That is, 3
    void printThree() {
    
     System.out.println(three); }

    public static void main(String[] args) {
    
    
        Test t = new Test();
        t.printThree();
    }
}

producción:

0
3

Proceso de implementación:

1、执行Test()
2、执行Test()中的super(),也就是Super()方法
3、然后执行Super()方法中的super(),也就是Object的构造方法
4、执行Super类的printThree()方法,因为被子类重写了,所以会调用子类的printThree()方法,输出tree变量的值0(是默认值,因为 int three = (int)Math.PI 还没被执行)
5、执行Test类中的 int three = (int)Math.PI 让three的值变为了3
6、再执行Test类中的printThree()方法,此时输出3

5. Finalización de Instancias de Clase

El objeto tiene un método protectdecorado , lo que significa que cualquier subclase puede llamar al método finalizede la superclase . finalizeCuando un objeto es inalcanzable (cuando ya no se usa), se reciclará y, antes de eso, la máquina virtual Java llamará a este método.

Características

1. finalizeEl método puede liberar recursos que la JVM no puede liberar, por lo que solo recuperar la memoria utilizada por el objeto no recupera todos los recursos que posee.

2. A diferencia del constructor, finalizelas llamadas no están ordenadas. En otras palabras, cuando se va a reciclar un lote de objetos, sus finalizemétodos se pueden llamar en cualquier orden, e incluso varios subprocesos pueden llamarlos simultáneamente.

3. A diferencia del constructor, la JVM no llamará automáticamente al finalizemétodo de la clase principal a menos que esté escrito en el programa.

4. Si finalizese lanza una excepción no detectada en el método, la excepción se ignorará y finalizela llamada al método finalizará, por ejemplo:

public class Test {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        testFinalize();
    }

    private static void testFinalize() throws InterruptedException {
    
    
        List<ObjectA> list = new ArrayList<>(10);
        for (int i = 0; i < 5; i++) {
    
    
            list.add(new ObjectA());
        }
        list = new ArrayList<>();
        System.gc();
        Thread.sleep(Long.parseLong("4000"));
        System.out.println("complete!");
    }
}
class ObjectA {
    
    
    @Override
    protected void finalize() {
    
    
        System.out.println("finalize() start");
        // 执行到这里后,因为异常将不会往下执行
        int a = 10 / 0;
        System.out.println("finalize() end");
    }
}

producción:

finalize() start
finalize() start
finalize() start
finalize() start
finalize() start
complete!

6. Descarga de Clases e Interfaces

Además de reclamar instancias de objetos mencionadas anteriormente, Java también puede reciclar clases e interfaces, es decir, "descargar" clases e interfaces. La descarga de clases no es necesaria, es solo una optimización que solo tiene sentido para aplicaciones que cargan muchas clases al principio y luego dejan de usarlas después de un tiempo.

Características

1. Si y solo si el cargador de clases se recicla, las clases y las interfaces que carga se pueden descargar

2. Las clases e interfaces cargadas por BootStrap Loader no se pueden descargar

7. Salida del programa

La salida del programa se produce en las dos situaciones siguientes:

1. Todos los subprocesos que no son demonios se terminan

2. Llamar a una clase Runtime.getRuntime().exit(n)o System.exit(n)método

Supongo que te gusta

Origin blog.csdn.net/weixin_44829930/article/details/121192093
Recomendado
Clasificación