Carga de subsistemas como JVM y mecanismo de delegación padre

Carga de subsistemas como JVM y mecanismo de delegación padre

Uno, subsistema de carga de clases

1. El subsistema de carga de clases es responsable de cargar archivos de clases desde el sistema de archivos o la red. El archivo de clases tiene un identificador de archivo específico al principio del archivo . La JVM no .classjuzga si necesita cargarse verificando si el el sufijo del archivo no es , sino hasta el principio del archivo La marca específica del archivo es el hexadecimal CA TE BA BE;

2. La información de clase cargada se almacena en un espacio de memoria que se convierte en el área de método . Además de la información de la clase, el área de método también almacena información del grupo de constantes en tiempo de ejecución y también puede incluir cadenas literales y constantes numéricas (esta parte de la información constante es la asignación de memoria de la parte del grupo de constantes del archivo de clase)

Aquí hay un diagrama de estructura de memoria JVM clásico: el rango de trabajo del cargador de clases está limitado a la mitad izquierda de la figura a continuación, y no incluye los objetos instanciados al llamar al constructor

  • Definición: La carga de clases se refiere a leer los datos binarios en el archivo .class de la clase en la memoria, colocarlos en el área de métodos del área de datos en tiempo de ejecución y luego crear un objeto java.lang.Class en el área de almacenamiento dinámico. Se utiliza para encapsular la estructura de datos de la clase en el área de métodos.
    Inserte la descripción de la imagen aquí

3. ClassLoader solo es responsable de la carga de archivos de clase. En cuanto a si puede ejecutarse, lo determina el motor de ejecución.

4. Si se llama al constructor para crear una instancia del objeto, su instancia se almacena en el área del montón

Desglose funcional
Inserte la descripción de la imagen aquí

Módulo de carga

1. Obtenga el flujo de bytes binarios que define esta clase a través del nombre completo de una clase;

2. Convierta la estructura de almacenamiento estática representada por este flujo de bytes en datos de tiempo de ejecución en el área de métodos;

3. Genere un objeto java.lang.Class que represente esta clase en la memoria como la entrada de acceso para varios datos de esta clase en el área de métodos.

El módulo de enlace se divide en tres partes, a saber, verificación, preparación y análisis.

verificación

1. El propósito es garantizar que la información contenida en el flujo de bytes del archivo de clase cumpla con los requisitos de la máquina virtual actual, para garantizar la exactitud de la clase cargada y no poner en peligro la seguridad de la propia máquina virtual.

2. Incluye principalmente cuatro verificaciones, verificación de formato de archivo, verificación de datos de origen, verificación de código de bytes y verificación de referencia de símbolo.

Listo

1. Asigne memoria para la variable de clase y establezca el valor inicial predeterminado de la variable de clase, es decir, el valor cero;

2. La estática modificada con final no se incluye aquí, porque final se asignará durante la compilación y se inicializará explícitamente en la fase de preparación;

3. La variable de instancia no se asignará ni se inicializará, la variable de clase se asignará en el área de método y la variable de instancia se asignará al montón de Java junto con el objeto.

Analizando

1. El proceso de convertir referencias de símbolos en el grupo constante en referencias directas.

2. De hecho, la operación de análisis suele ir acompañada de la JVM después de que se ejecuta la inicialización.

3. La referencia de símbolo es un conjunto de símbolos para describir el objetivo referenciado. La forma literal de la aplicación de símbolos está claramente definida en el formato de archivo de clase de "Especificación de máquina virtual Java". Una referencia directa es un puntero que apunta directamente al objetivo, un desplazamiento relativo o un identificador que está ubicado indirectamente al objetivo.

4. La acción de análisis es principalmente para clases o interfaces, campos, métodos de clase, métodos de interfaz, tipos de métodos, etc. Correspondiente a CONSTANT_Class_info / CONSTANT_Fieldref_info, CONSTANT_Methodref_info, etc. en el grupo constante.

Inicializar el módulo, la fase de inicialización es el proceso de ejecución del método constructor de clases clinit ()

1.clinit () significa "método de inicialización de clase o interfaz", tenga en cuenta que no se refiere al constructor init ()

2. No es necesario definir este método, es el compilador javac el que recopila automáticamente las acciones de asignación de todas las variables de clase en la clase y fusiona las declaraciones en el bloque de código estático.

3. Notamos que si no hay una variable estática c, entonces no habrá ningún método clinit en el archivo de código de bytes.

Inserte la descripción de la imagen aquí
La forma en que el programa java usa la clase se divide en: uso activo y uso pasivo, es decir, si se llama al método clinit ()

Utilice activamente la inicialización de la tercera etapa (módulo de inicialización) en el sistema de carga de clases, es decir, se llama al método clinit () en la fase de inicialización

Y el uso pasivo no llamará

Uso activo, dividido en siete situaciones

1. Crea una instancia de la clase.

2. Acceda a variables estáticas de un determinado tipo o interfaz, o asigne valores a variables estáticas

3. Llame al método estático de la clase.

4. Reflexión como Class.forName (com.dsh.jvm.xxx)

5. Inicializar una subclase de una clase

6. La clase que está marcada como la clase de inicio cuando se inicia la máquina virtual Java.

7. El soporte de lenguaje dinámico proporcionado por JDK 7: el resultado del análisis de java.lang.invoke.MethodHandle instancia REF_getStatic, REF_putStatic, REF_invokeStatic handle correspondiente a la clase no se inicializa, luego se inicializa

Excepto por los siete casos anteriores, otros métodos de uso de clases de Java se consideran un uso pasivo de clases y no conducirán a la inicialización de clases.

La máquina virtual debe asegurarse de que el método clinit () de una clase esté sincronizado y bloqueado en varios subprocesos.

Tipos de cargadores de clases

Inserte la descripción de la imagen aquí

Es decir, una clase solo necesita ser clinit una vez, y luego la información interna de la clase se almacena en el área de método.

  • Rol: cargar archivos de clase, referencia en la pila, ejemplos específicos en el montón
  • El virtualizador viene con tres tipos de cargadores
    • Cargador de clase de inicio (raíz)
    • Cargador de clases extendido
    • Nota del cargador de aplicaciones (cargador de clases del sistema)
      :
  • Hay muchos tipos de cargadores de clases, tres o cuatro (el cuarto es un cargador definido por usted mismo, heredando el cargador de clases ). Los tres que vienen con el sistema son:
  1. Bootstrap, escrito en C ++

    • Esta carga de clases está implementada en lenguaje C / C ++ y está anidada dentro de la JVM
    • Se utiliza para cargar la biblioteca central de Java (JAVA_HOME / jre / lib / rt.jar / resources.jar o el contenido de la ruta sun.boot.class.path) y se utiliza para proporcionar las clases que necesita la propia JVM.
    • No hereda de java.lang.ClassLoader, no hay un cargador principal
    • Cargar clases de extensión y cargador de clases de aplicación, y designar como su cargador principal, es decir, ClassLoader
    • Por razones de seguridad, el cargador de clases de inicio de BootStrap solo carga clases cuyos nombres de paquete comienzan con java, javax, sun, etc.
  2. Cargador de clases de extensión (Extensión), escrito en Java

    • Escrito en lenguaje Java e implementado por sun.misc.Launcher $ ExtClassLoader.
    • Derivado de la clase ClassLoader, no heredado
    • Cargue la biblioteca de clases desde el directorio especificado por la propiedad del sistema java.ext.dirs, o cargue la biblioteca de clases desde el subdirectorio jre / lib / ext (directorio de extensión) del directorio de instalación de JDK. Si el JAR creado por el usuario se coloca en este directorio, el cargador de clases extendido también lo cargará automáticamente.
  3. Cargador de clases de aplicación (AppClassLoader)

    • Escrito en lenguaje Java e implementado por sun.misc.Launcher $ AppClassLoader.
    • Derivado de la clase ClassLoader, no heredado
    • Es responsable de cargar la biblioteca de clases en la ruta especificada por la variable de entorno classpath o la propiedad del sistema java.class.path
    • Este cargador de clases es el cargador de clases predeterminado en el programa . En términos generales, las clases de aplicaciones Java las carga
    • El cargador de clases se puede obtener a través del método ClassLoader # getSystemClassLoader ()

    Cargador de clases definido por el usuario:

    En el desarrollo diario de aplicaciones Java, la carga de clases se realiza casi por la coordinación de los tres tipos de cargadores antes mencionados, si es necesario, puede personalizar los cargadores de clases para personalizar la forma en que se cargan las clases.

    ¿Por qué desea personalizar el cargador de clases?

    • Clase de carga de forma aislada
    • Modificar el método de carga de clases
    • Fuente de carga de la extensión
    • Prevenir fugas de código fuente

Lo que creamos cuando somos nuevos es el cargador de clases de aplicaciones (AppClassLoader).

public class Car {
    
    
    public static void main(String[] args) {
    
    
        Car car1 = new Car();
        Car car2 = new Car();
        Car car3 = new Car();

        System.out.println(car1.hashCode());
        System.out.println(car2.hashCode());
        System.out.println(car3.hashCode());

        Class<? extends Car> aClass = car1.getClass();

        System.out.println(aClass.getClassLoader());    // 应用程序加载器 AppClassLoader
        System.out.println(aClass.getClassLoader().getParent()); // 扩展类加载器 ExtClassLoader       D:\jdk1.8\jre\lib\ext/*.jar
        System.out.println(aClass.getClassLoader().getParent().getParent());  // null   1. 不存在, 2. java程序获取不到  D:\jdk1.8\jre\lib\rt.jar

    }

Nota:

  • Si se trata de clases propias del JDK (Object, String, ArrayList, etc.), el cargador utilizado es el cargador Bootstrap; si escribe su propia clase, se usa el cargador AppClassLoader; el cargador de extensiones es el programa responsable de actualizar java. se lleva a cabo la carga de clase del paquete
  • En la salida, sun.misc.Launcher es el programa de entrada para llamadas relacionadas con JVM
  • El número de cargadores de Java es 3 + 1. Los primeros tres están integrados en el sistema, los usuarios pueden personalizar la forma en que se carga la clase heredando Java. Lang. ClassLoader

JVM indica si dos objetos de clase son de la misma clase

1. Dos condiciones necesarias para saber si dos objetos de clase existen en la misma clase en jvm

  • El nombre de clase completo de la clase debe ser coherente , incluido el nombre del paquete.
  • Incluso si el nombre de clase completo de la clase es el mismo, se requiere que el ClassLoader (refiriéndose al objeto de instancia de ClassLoader) que carga esta clase debe ser el mismo ; ya sea el cargador de clases de arranque o la definición del cargador de clases

2. En otras palabras, en jvm, incluso si estos dos objetos de clase (objetos de clase) se originan en el mismo archivo de clase y son cargados por la misma máquina virtual, siempre que los objetos de instancia de ClassLoader que los carguen sean diferentes, entonces estos dos objetos de clase Tampoco es igual.

3. Para la referencia al cargador de clases, la JVM debe saber si el cargador de clases de inicio o el cargador de clases de usuario carga un tipo. Si es un tipo de carga del cargador de clases de usuario, la JVM será una referencia al cargador de clases como parte del tipo de información almacenada en el área de métodos . Al resolver referencias de un tipo a otro, la JVM debe asegurarse de que los cargadores de los dos tipos sean los mismos.

2. Mecanismo de delegación de los padres

Inserte la descripción de la imagen aquí
Nota:

  • Mecanismo de delegación de los padres: "Mi papá es Li Gang, pídele algo a mi papá".
    Por ejemplo: si necesita usar una clase A.java, primero vaya al cargador raíz de Bootstrap superior para encontrarlo. Si lo encuentra, puede usarlo. Si no puede encontrarlo, baje un nivel más. Vaya al cargador de extensiones para encontrarlo. Si lo encuentra, úselo, pero no puede encontrarlo. Para otra capa, vaya a AppClassLoader para encontrarlo y úselo si lo encuentra. Si no puede encontrarlo, informará "CLASE NO ENCONTRADA EXCEPCIÓN".
//测试加载器的加载顺序
package java.lang;

public class String {
    
    

    public static void main(String[] args) {
    
    

        System.out.println("hello world!");

    }
}

/*
* output:
* 错误: 在类 java.lang.String 中找不到 main 方法
* */

El código anterior es para probar el orden del cargador: el cargador Bootstrap se carga primero. Dado que hay una clase java.lang.String en la JVM, esta clase se cargará primero en lugar de la clase escrita por usted mismo, y hay nada en esta clase. método principal, por lo que informará "No se puede encontrar el método principal en la clase java.lang.String".

Esta pregunta implica, si hay dos clases idénticas, ¿cuál usará Java? Si usa el java.lang.String definido por el usuario, entonces no use este tipo de programa, se producirán todos los errores. Por lo tanto, para asegurarse de que el código fuente escrito por el usuario no contamine el código fuente que viene con la fábrica de Java, se proporciona una especie de " padres ". Mecanismo de "delegación" para garantizar la "seguridad de la zona de pruebas" . Es decir, búsquelo primero y utilícelo primero.

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_43803285/article/details/115281657
Recomendado
Clasificación