Máquina virtual JVM && carga de clase (1)

Máquina virtual

Introducción a la máquina virtual

La Java Virtual Machine (JVM) es una computadora abstracta que ejecuta programas java. Es una especificación de equipo informático y puede implementarse de diferentes maneras. El programa java puede implementarse multiplataforma al ejecutarse en la JVM. Una vez compilado, se ejecuta en todas partes. Los diferentes sistemas operativos tienen diferentes Versión JDK, llamando al método JNI para lograr el método de llamar a diferentes sistemas operativos

gráfico LR A [archivo fuente java] B [código de bytes binarios de clase] C [JVM] D ((interfaz nativa de Java) F [método nativo de Windows] H [método nativo de Linux] I [método nativo de macOS] A-.compile .-> B B-.Cargar .-> C C-. Abrir archivo .-> D D-.windows-JDK .-> F D-.linux-JDK .-> H D-.macOS-JDK .-> Yo

La máquina virtual Java no está vinculada al lenguaje, incluido Java. Solo está vinculada al formato de archivo binario específico del archivo de clase. El archivo de clase contiene el conjunto de instrucciones de la máquina virtual y la tabla de símbolos y otra información adicional.

gráfico LR A [programa java] B [programa JRuby] C [programa Groovy] D [compilador java] E [compilador JRuby] F [compilador Groovy] H [código de bytes] I [máquina virtual Java] A-. * .java archivo .-> D B-. *. archivo rb .-> E C-. *. archivo maravilloso .-> F D-> H E-> H F-> H H-. *. archivo de clase .-> I

Productos de máquinas virtuales

  1. Sun HotSpot (JVM)
  2. BEA JRocket
  3. IBM J9
  4. Microsoft JVM
  5. Google Android Dalvik

Archivos de clase

El archivo de clase es una secuencia binaria con unidades básicas de 8 bits. Los datos se organizan en orden estricto en el archivo de clase sin separadores. Si supera los 8 bits, se almacena primero en el orden superior.

Composición del archivo de clase

  1. conjunto de instrucciones de máquina virtual java
  2. Tabla de símbolos
  3. Otra información auxiliar

Piscina constante

Después de compilar el código Java, el archivo de clase no guarda los diversos métodos y el diseño final de los campos en la memoria. Debido a que la dirección real de la clase referenciada no se conoce durante la compilación, solo se puede reemplazar por una descripción de símbolo. Cuando se ejecuta, debe obtener la referencia de símbolo correspondiente del grupo constante del archivo de clase y luego resolver la dirección de memoria específica durante la creación de la clase o el tiempo de ejecución

Es decir, cuando se carga la clase, se debe asignar una dirección específica en la memoria, de modo que cuando se resuelva, la referencia del símbolo se pueda reemplazar con la dirección real.

El grupo constante de archivos de clase almacena principalmente dos tipos:

  • Literales Los literales son conceptos constantes cercanos al nivel del lenguaje Java, como cadenas de texto, declaración de valores constantes finales, etc.
  • Las referencias simbólicas incluyen principalmente nombres completos de clases e interfaces, nombres de campo y descriptores, nombres de métodos y descriptores

Carga de clase de máquina virtual

Carga de clases en el espacio vital de JVM

gráfico LR A [Carga] B [Verificación Verificación] C [Preparación Preparación] D [Resolución] E [Inicialización] F [Utilizando Usando] G [Descarga] A-> B D-> E E-- > F F-> G subgraph connect B-> C C-> D end

Cargando

Lo que hace el proceso de carga es:

  • Obtener flujo de bytes binarios
  • La estructura de almacenamiento estático se transforma en la estructura de datos de tiempo de ejecución del área de método.
  • Genere un objeto de clase en el objeto de montón de Java como la entrada del área de método

Hay formas de obtener una secuencia de bytes binarios en Java

  • Obtenido de Zip, Jar, War y otros archivos de formato
  • Obtenga la aplicación Applet de la web
  • Cálculo de tiempo de ejecución y generación, tecnología de proxy dinámico
  • La aplicación JSP genera la clase de clase correspondiente.

Verificar

La verificación es el primer paso de la conexión. Para garantizar que la información contenida en la secuencia de bytes en el archivo de Clase cumpla con los requisitos de la JVM, la fase de verificación se divide en las siguientes etapas.

  • La verificación del formato de archivo verifica que la ID del archivo sea correcta, si el número de versión puede coincidir con la JVM actual y si las constantes en el grupo de constantes tienen tipos no admitidos.Después de esta etapa de verificación, el flujo de bytes ingresará al área del método para el almacenamiento. La verificación posterior solo se basa en la verificación de la estructura de almacenamiento del área del método y no verificará el flujo de bytes.
  • La verificación de metadatos es principalmente para analizar la semántica de la descripción del código de bytes, para garantizar la especificación del lenguaje Java de símbolos, herencia de clases, implementación de clases abstractas, etc.
  • Verificación de bytecode
  • Verificación de referencia de símbolo Esta etapa ocurre cuando la referencia de símbolo se reemplaza con una referencia directa, para verificar la verificación de coincidencia de la referencia de símbolo, etc.

Listo

La etapa de preparación es asignar memoria a la clase y establecer la inicialización Clint de las variables de clase. La memoria utilizada por estas variables se asigna en el área de método, pero la asignación de memoria de las variables de clase (estática modificada) no incluye variables de instancia. A medida que se instancia la clase, se asigna en el montón

: Inicialización de la clase de la variable estática principal clase principal subclase del bloque estático subclase de la variable estática bloque estático

: Inicialización de objetos Inicializa variables de clase padre, constructor de clase padre. . . . . .

Analizando

El propósito de la resolución es reemplazar las referencias de símbolos en el grupo constante con referencias directas

Análisis de campo

class A extends B implements C{
    private String str; //字段的解析
}
gráfico TB A {A puede coincidir} B {B puede coincidir} C {C puede coincidir} A-> | Sí | E [Fin] A-> | No | C interfaz de subgrafo C-> | Sí | F (final) subgrafo final clase padre C-> | No | B B-> | Sí | I (final) B-> | No | J ((excepción de lanzamiento)) final

Análisis de método de clase

  • Encuentra esta categoría primero
  • Luego busque recursivamente en la clase padre
  • Lista de interfaces implementadas en la clase y sus interfaces principales

Análisis de método de interfaz

  • Encuentra esta interfaz primero
  • Encuentra recursivamente en la interfaz principal de la interfaz

Cargador de clase

Obtenga el flujo de bytes binarios que describe la clase por el nombre completo de la clase y coloque la acción en esta etapa de cargar la clase fuera de la máquina virtual para implementarla, de modo que la aplicación pueda decidir si necesita obtener la clase que necesita para implementar esta acción. Sé un cargador de clases.
Hay una clase abstracta Clase ClassLoader en Java.
El resumen principal de la clase ClassLoader.loadClass es:

  • Solo un hilo puede cargar una clase a la vez
  • Antes de cargar la clase, comprobará si se ha cargado, solo se pueden cargar aquellos que no se han cargado.
  • El que puede cargar el cargador principal nunca se entregará al cargador secundario. Por qué es así para garantizar la seguridad, por ejemplo, si escribe una clase subyacente de Java con el mismo nombre, como java.util.ArrayList, a través del cargador secundario a la memoria , ¿No es tan complicado? Cuando llegue el momento, se implantará un código de virus y la persona que lo use no será GG.
  • El cargador secundario solo cargará el cargador primario si no se puede cargar.

Tipo de cargador

Desde la perspectiva de la JVM, solo hay cargadores de clase 2. Uno es que Bootstrap ClassLoader está implementado por el lenguaje C ++. Hay otro tipo de cargador de clases, implementado por lenguaje java, independiente de JVM, todos heredan java.lang.ClassLoader

Si lo miramos desde nuestra perspectiva de desarrollo, se divide en cargadores de 3 clases:

  • Bootstrap ClassLoader inicia el cargador de clases, que es responsable de cargar las bibliotecas de clases en Java_Home / lib en la memoria. Debido a los detalles de implementación local involucrados en la máquina virtual, todos nuestros desarrolladores no pueden obtener una referencia al cargador de clases.
  • Extension ClassLoader El cargador de clases de extensión es responsable de cargar Java_Home / lib / ext o la clase especificada por la variable de sistema java.ext.dirs en la memoria
//Launcher.class文件中
static class ExtClassLoader extends URLClassLoader {
        private static volatile Launcher.ExtClassLoader instance;

        public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
            if (instance == null) {
                Class var0 = Launcher.ExtClassLoader.class;
                synchronized(Launcher.ExtClassLoader.class) {
                    if (instance == null) {
                        instance = createExtClassLoader();
                    }
                }
            }

            return instance;
        }
     ....        
}
  • Application ClassLoader, el cargador de pollo de la clase de aplicación, que es responsable de cargar la biblioteca de clases especificada en la ruta del sistema ClassPath en la memoria, este cargador de clases es
    el valor de retorno del método estático getSystemClassLoader en la clase ClassLoader
 //java/lang/ClassLoader.java 文件中
 public static ClassLoader getSystemClassLoader() {
        initSystemClassLoader();
        if (scl == null) {
            return null;
        }
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkClassLoaderPermission(scl, Reflection.getCallerClass());
        }
        return scl;
    }
gráfico BT A [Bootstrap 加载 器] B [ExtClassLoader] C [AppClassLoader] D [UseClassLoader1] F [UseClassLoader2] B -> A subgraph 非 JVM C -> BD -> CF -> C end

Si estás interesado, puedes hacerlo tú mismo

String appClassLoaderPath = System.getProperty("java.class.path");
System.out.println(appClassLoaderPath);
String extClassLoaderPath = System.getProperty("java.ext.dirs");
System.out.println(extClassLoaderPath);
String bootClassLoaderPath = System.getProperty("sun.boot.class.path");
System.out.println(bootClassLoaderPath);

Delegación de padres

¿Qué es la delegación de padres?

  • Si un cargador de clases recibe una solicitud de carga de clase, el cargador no se cargará, pero lanzará la solicitud al cargador de clases padre, por lo que todas las solicitudes de carga de clase llegarán al cargador de clase superior
  • Solo cuando el cargador de clases principal no puede encontrar la clase requerida dentro de su alcance, el resultado se enviará al cargador secundario, y el cargador secundario está intentando cargarse

Cómo interrumpir

¡Escriba usted mismo un cargador de clases y reescriba el método loadClass!

¿Por qué usar la delegación principal?

  • Para cualquier clase, es necesario establecer su unicidad en la máquina virtual Java mediante el cargador de clases que la carga y la clase misma. Cada cargador de clases tiene un espacio de nombres de clase independiente. Para determinar si dos clases son "iguales", debe estar bajo la premisa de que las dos clases son cargadas por el mismo cargador de clases.
  • Basado en el diseño del modelo de delegación principal, entonces el problema de la clase básica en Java, como la clase Object repetida muchas veces, no existirá, porque después de pasar por las capas, BootstrapClassLoader responderá a la solicitud de carga. Solo habrá una clase Object cargada, de lo contrario, si el usuario escribe una clase java.lang.Object y la coloca en ClassPath, habrá muchas clases Object, de modo que el comportamiento más básico en el sistema de tipos Java no puede ser Garantía, la aplicación también será un desastre.

Supongo que te gusta

Origin www.cnblogs.com/burg-xun/p/12689079.html
Recomendado
Clasificación