comprensión JVM (a): la carga del cargador de clases los principios y mecanismos de archivos de clases

Transferencia: https://www.jianshu.com/p/52c38cf2e3d4

comprensión JVM (a): la carga del cargador de clases los principios y mecanismos de archivos de clases

Anthony _Anthony
12018.11.10 10:16:40 número de palabras leídas 4.361 3.731

1 arquitectura JVM arquitectura general

Antes de entrar en el análisis de cargador de clases, primer vistazo a la JVM en general la arquitectura:

 
arquitectura JVM

JVM se divide en tres subsistemas principales

(1) un subsistema de cargador de clases (2) el área de datos de tiempo de ejecución (3) de motor de ejecución

1. El subsistema de cargador de clases

 

Java función de carga dinámica de clases es manejado por el subsistema de cargador de clases. Cuando se ejecuta por primera vez en referencia a una clase (tiempo de compilación no), se carga, enlace e inicializar el archivo de clase.

1.1 Carga: la carga de clases de montaje de este modo. Start cargador de clases (BootStrap clase Loader), cargador de clases extendida (clase Loader extensión) y cargador de clases de la aplicación (Aplicación cargador de clases) Estos tres tipos de ayuda cargador de clases cargadas. 1. Iniciar el cargador de clases - responsable de cargar las clases de la ruta de clase de arranque, nada más que rt.jar. El cargador se le dará la más alta prioridad. 2. Extensión del cargador de clases - es responsable de ext carga (jre \ lib) .3 clases dentro del cargador de clases de la aplicación - el responsable de cargar la ruta de clase a nivel de aplicación, en relación con las variables de entorno de ruta anteriores cargador de clases, etc. vamos a seguir el algoritmo de nivel de la Comisión (algoritmo de jerarquía de delegación) archivos de clase cargada, para explicar esto más adelante.

El proceso de carga se ha completado tres cosas importantes:

  • Para obtener un flujo de bytes tales binario definido por el nombre completo de la clase

  • La estructura de clase de almacenamiento estático representado por el flujo de bytes en las estructuras de datos de tiempo de ejecución en la zona de método

  • Generación de un representante de los mismos en la pila de área de objeto java.lang.Class como la entrada método de acceso de estas estructuras de datos.

1.2 Enlaces:

  1. Compruebe el código de bytes verificador verifica el código de bytes generada es correcta. Si la comprobación falla, obtendremos un error de paridad.

Formato de archivo de validación: byte de validación, de bytes de verificación de acuerdo con la especificación actual formato de archivo de clase, la máquina virtual actual puede procesar. Después se pasa la verificación, el flujo de bytes entrará en la región del método de almacenamiento de memoria.

Metadatos de validación: método de verificación sobre la base de la estructura de almacenamiento de la región, el código de bytes de verificación semántica, para asegurar que la información de metadatos no cumple con la especificación del lenguaje Java no existe.

verificación Bytecode: método de verificación basado en la estructura de almacenamiento de la región, el análisis de los datos de flujo y flujo de control del método de pruebas para asegurar que la clase en tiempo de ejecución no haría que el funcionamiento del peligro de la máquina virtual.

Verificación de referencias simbólicas: método de verificación sobre la base de la estructura de almacenamiento de la región, se produjo en la etapa de análisis, para asegurar un éxito de referencias simbólicas determinación de referencia directamente a su operación de análisis con el fin de asegurar la ejecución normal. En otras palabras, basándose en la información que no sea el juego del cheque en sí.

  1. Preparación - asignar memoria e inicializar los valores por defecto para todas las variables estáticas.

valor int public static = 33;

De acuerdo con este código de procedimiento de asignación de dos veces, primero etapa hemos mencionado anteriormente, este tiempo se le asigna el valor 0, el valor = 33 Este proceso ocurre en la clase constructor <clinit> (método).

  1. Todas las referencias de memoria se resuelven símbolos región método original (Método Area) se sustituye por referencia.

Para dar un ejemplo para ilustrar, citado clase com.sbbic.Person clase com.sbbic.Animal, en tiempo de compilación, la clase Persona animal no conoce las direcciones de memoria real, y por lo tanto sólo se puede utilizar para representar el com.sbbic.Animal Animal dirección de memoria real. En la fase de resolución, JVM puede resolver las referencias simbólicos a las direcciones de memoria com.sbbic.Animal determinar la clase verdadera (si la clase no se ha cargado antes, la primera carga).

Hay los cuatro siguientes: el análisis sintáctico, el análisis de los campos, o el método de clase de interfaz de método de interfaz analítica, analítica

1.3 Inicialización: Esta es la fase final de la carga de clases, donde todas las variables estáticas serán asignados un valor inicial, y un bloque estático será ejecutado.

java, para la fase de inicialización, y solamente la siguiente cinco casos ** sólo para necesidades inmediatas de la inicialización de la clase:

  • Usar la palabra clave new para crear una instancia de un objeto, el acceso, o establecer un campo estático de una clase (las modificaciones finales, las excepciones se han colocado en una piscina constante de optimización del compilador), llama al método clase inicializar los campos estáticos o clase en la que los métodos estáticos;

  • tiempo de inicialización de clase, si la clase padre no se ha inicializado, la primera inicialización de la clase padre de disparo;

  • Uso java.lang.reflect paquete se refleja cuando se le llama, si la clase no se ha inicializado, la primera inicialización;

  • Cuando se inicia la máquina virtual, el usuario primero inicializar la clase principal a ejecutar (que contiene principal);

  • Después de JDK 1.7, correspondiente a la última instancia, si el resultado del análisis es java.lang.invoke.MethodHandle REF_getStatic, REF_putStatic, mango método REF_invokeStatic, y una clase donde no se inicializa este método, la primera inicialización;

2. área de datos en tiempo de ejecución (runtime área de datos)

El área de datos en tiempo de ejecución se divide en cinco componentes principales:

① método de código de área (hilos de acción) estática constante de las variables JIT (tiempo compilador) compilado es también la zona método para almacenar

El lugar de memoria montón principal ② (cuota de hilos) la recolección de basura

Bytecode ③ hilo actual de indicador de posición de contador de programa de ejecución

④ Java Virtual Machine pila (memoria de pila): variables locales, tipos de datos, y la variable de referencia objeto de memoria heap básica

⑤ pilas de métodos nativos (Stack C): prevé la JVM utilizando métodos nativos de servicio

 

3. Motor de Ejecución

Asignado al área de datos de tiempo de ejecución del código de bytes ejecutado por el motor de ejecución. El motor de ejecución lee el código de bytes y la realización de tramos. 3.1 intérprete: interpretación de código de bytes intérprete rápidamente, pero la implementación es muy lento. La desventaja es que el intérprete, cuando un método se llama varias veces, cada vez necesitan re-interpretación.

3.2 compilador: el compilador JIT elimina las desventajas de la intérprete. motor de ejecución utilizando una conversión de código de bytes intérprete, pero si un código duplicado utilizando un compilador JIT para compilar todo el código de bytes de código nativo. código nativo directamente para repetir la llamada al método, lo que mejora el rendimiento del sistema. . Un generador de código intermedio - generar intermedio código código optimizador b - c responsable de optimizar el código intermedio generado por encima del generador de códigos de destino - es responsable de la generación de código de máquina o código nativo detector d (la Profiler) - un componente particular , responsable de encontrar un método llamado varias veces.

3.3 recolector de basura: recoger y eliminar objetos no referenciados. La recolección de basura puede ser desencadenada por una llamada a "System.gc ()", pero no garantiza hace la recolección de basura. la recolección de basura de la JVM, que los objetos creados por la nueva colección única palabra clave. Por lo tanto, si no se utiliza para crear nuevos objetos que se pueden utilizar para llevar a cabo la función de finalización de limpieza. Java Native Interface (JNI): JNI va a interactuar con las bibliotecas de métodos nativos y proporcionar la biblioteca local del motor de ejecución requerido. bibliotecas de métodos nativos: es una colección de bibliotecas nativas requeridas prestaciones del motor.

A continuación, sabe JVM a través de un pequeño programa:

package com.spark.jvm;

/**

* 从JVM调用的角度分析java程序堆内存空间的使用:

* 当JVM进程启动的时候,会从类加载路径中找到包含main方法的入口类HelloJVM

* 找到HelloJVM会直接读取该文件中的二进制数据,并且把该类的信息放到运行时的Method内存区域中。

* 然后会定位到HelloJVM中的main方法的字节码中,并开始执行Main方法中的指令

* 此时会创建Student实例对象,并且使用student来引用该对象(或者说给该对象命名),其内幕如下:

* 第一步:JVM会直接到Method区域中去查找Student类的信息,此时发现没有Student类,就通过类加载器加载该Student类文件;

* 第二步:在JVM的Method区域中加载并找到了Student类之后会在Heap区域中为Student实例对象分配内存,

* 并且在Student的实例对象中持有指向方法区域中的Student类的引用(内存地址);

* 第三步:JVM实例化完成后会在当前线程中为Stack中的reference建立实际的应用关系,此时会赋值给student

* 接下来就是调用方法

* 在JVM中方法的调用一定是属于线程的行为,也就是说方法调用本身会发生在线程的方法调用栈:

* 线程的方法调用栈(Method Stack Frames),每一个方法的调用就是方法调用栈中的一个Frame,

* 该Frame包含了方法的参数,局部变量,临时数据等 student.sayHello();

 */

public class HelloJVM { //在JVM运行的时候会通过反射的方式到Method区域找到入口方法main public static void main(String[] args) {//main方法也是放在Method方法区域中的 /** * student(小写的)是放在主线程中的Stack区域中的 * Student对象实例是放在所有线程共享的Heap区域中的 */ Student student = new Student("spark"); /** * 首先会通过student指针(或句柄)(指针就直接指向堆中的对象,句柄表明有一个中间的,student指向句柄,句柄指向对象) * 找Student对象,当找到该对象后会通过对象内部指向方法区域中的指针来调用具体的方法去执行任务 */ student.sayHello(); } } class Student { // name本身作为成员是放在stack区域的但是name指向的String对象是放在Heap中 private String name; public Student(String name) { this.name = name; } //sayHello这个方法是放在方法区中的 public void sayHello() { System.out.println("Hello, this is " + this.name); } } 

Principios y mecanismos de cargador de clases cargar el archivo de clase

La siguiente parte, terminando de "análisis en profundidad JavaWeb Inside"

Clase cargador de clases responsable de la carga en la JVM, y está determinada por el cargador de clases de carga (nivel de prioridad de los padres mecanismo de carga). Otra tarea es la clase de código de bytes JVM reinterpretado como un formato unificado requisitos

análisis de la estructura de clase 1.Classloader

(1) se compone de cuatro métodos principales, a saber defineClass, FindClass, loadClass, resolveClass

  • Cuando <1> defineClass (byte [], int, int) el byte a byte de la corriente de análisis de objetos JVM clase puede ser reconocido (llamar directamente objeto Class es un método que tiene no resuelve, esto va a resolver el objeto real en una instancia resolver)
  • <2> FindClass, por el nombre de clase para cargar el objeto clase correspondiente. Cuando ponemos en práctica cargador de clase personalizada por lo general reemplazar este método, encontrar el archivo de código de bytes basado en el nombre de la clase entrante correspondiente, y llamando al análisis sintáctico Clase exclusiva defineClass
  • <3> Usted puede cargar una clase llamando a este método de ejecución loadClass (Como las clases se cargan dinámicamente en la JVM, cuánto se carga con?)
  • <4> resolveClass llamada manualmente se añadió esta clase, para que la JVM está vinculado (Para resolver resolver esta categoría?)

(2) implementar un cargador de clases en general a medida heredará clase URLClassLoader, porque esta clase implementa la mayoría de los métodos.

2. Errores comunes en las clases de carga

(1) ClassNotFoundException:

Jvm por lo general un archivo de código byte que se carga en memoria cuando no hay bytecodes (por ejemplo forName, loadClass similares) encontrado

(2) NoClassDefFoundError:

Por lo general, utilizar la nueva palabra clave, referencias a atributos de una clase, hereda una clase o interfaz, pero la JVM carga inusual estas clases no existen estas clases

(3) UnsatisfiedLinkErrpr:

Los métodos nativos no pueden encontrar la máquina lib

3. cargador de clases común (libros aquí, de hecho, se carga Tomcat servlet utilizando el análisis de cargador de clases)

(1) AppClassLoader:

carga ruta de clases JVM de clases y clases básicas tomcat

(2) StandardClassLoader:

ClassLoader tomcat contenedor de carga, mientras que, además webAppClassLoader loadClass, la clase no se encuentra en la ruta de clase JVM, en PackageTriggers (una matriz de cadenas, el paquete contiene un conjunto de cadena de nombre no puede ser utilizado webAppClassLoader cargado clases), entonces el siguiente, por la carga cargado (Nota: el método StandardClassLoader loadClass no cubre, por lo que su carga AppClassLoader cargado clase y no hay diferencia, y también utilizando regresado getClassLoader AppClassLoader) (por otra parte, si la aplicación web directamente en el directorio de Tomcat webapp bajo la aplicación pasará StandardClassLoader cargado, presumiblemente porque PackageTriggers directorio webapp en?)

(3) webAppClassLoader como:

aplicaciones web como clase servlet de carga (ver P169 proceso loadClass regla)

4. cargador de clase personalizada

(1) requiere el uso de cargadores de clases personalizados

  • La <1> no System.getProperty ( "java.class.path") AppClassLoader archivo de clase no se puede encontrar (método LoaderClass ruta de clase única a un nombre de la clase particular de la clase bajo carga), cuando los archivos de clase de código de bytes no es ClassPath necesitará un cargador de clases personalizada
  • <2> cargador de clases necesidades de ciertos tratamientos especiales
  • <3> mecanismo eficaz para la definición de la clase, la clase que se han modificado para recarga, para lograr el despliegue térmica

(2) se carga desde el archivo de clase define la ruta

  • <1> cierta carga de clases a partir de una fuente en particular: encontrar métodos reescribir el código para una clase en particular o una clase byte derivado en particular obtenido por clase y devolviendo defineClass (cargador de clases JVM debe cumplir con las especificaciones otros utilizando las cargas cargador de clases padre todavía )
  • <2> es un archivos de clase de carga superior (por ejemplo, a través de la red transmite archivos cifrados byte clase de código): FindClass encriptada antes de la carga

La clase de implementación de despliegue en caliente:

  • (1) Dos instancias de la misma misma clase cargador de clases de carga, JVM también identificaron dos
  • (2) no se pueden repetir de carga de la misma clase (el mismo nombre completo, y utilizar el mismo cargador de clases), será un error
  • (3) no debería cargar dinámicamente clases, ya que el objeto después de canto referencias, estructura de la propiedad del objeto a ser modificado causa problemas

Por esta razón todos los posibles problemas al utilizar diferentes clases de los mismos archivos de carga del cargador de clases de clases obtenidas, JVM será tratada como dos clases diferentes, utilizando el patrón Singleton, reparto: atención.

6 matriz modelo de delegación cargador de clases

Cuando un cargador de clases recibe una petición para cargar una clase, solicitará el primer delegado al cargador de clases padre a cargar cada cargador de clases de nivel es cierto, por lo que en última instancia todas las clases deben ser transferidos solicitud de carga cuando la capa superior en el cargador de clases de arranque (en arranque cargador de clases), sólo cuando el cargador de clases padre para cargar la solicitud de realimentación no se puede completar en esta columna (que no existe dentro de esta clase el rango de búsqueda), los intentos para carga sub-clase para cargar solamente. Su diagrama de jerarquía es la siguiente:

 

No es difícil encontrar el tipo de beneficios que se derivan de la carga:

Evitar cargas repetidas, la clase padre se ha cargado, no es necesario cargar de nuevo las subclases

Más seguro, una buena solución al problema de la base de clase unificada de cada cargador de clases, si no se utiliza de esta manera, el usuario puede definir el cargador de clases para cargar el API del núcleo, traerá los riesgos relevantes.

A continuación, vamos a ver cómo se implementa el modelo de los padres delegado:

 protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先先检查该类已经被加载过了 Class c = findLoadedClass(name); if (c == null) {//该类没有加载过,交给父类加载 long t0 = System.nanoTime(); try { if (parent != null) {//交给父类加载 c = parent.loadClass(name, false); } else {//父类不存在,则交给启动类加载器加载 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { //父类加载器抛出异常,无法完成类加载请求 } if (c == null) {// long t1 = System.nanoTime(); //父类加载器无法完成类加载请求时,调用自身的findClass方法来完成类加载 c = findClass(name); sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } } 

Aquí están algunos zapatos para niños pedirán, JVM sabe cómo un cargador de clases padre es un cargador? Si tiene alguna pregunta sobre esto, por favor volver a ver de nuevo.

Características del cargador de clases 7

Al ejecutar cualquier programa, siempre debe empezar desde el cargador de aplicaciones para cargar la clase especificada.

Tras la recepción de una solicitud de carga de clase de clase, siempre los primeros en probar su cargador de clases padre.

Bootstrap Loader es cargador de clase superior, su cargador matriz es nulo.

8 con tres tipos cargable

Carga de la clase de aplicación principal que contiene método main () es inicializado por la línea de comandos la JVM inicio.

Cargado dinámicamente por el Class.forName (método) se realiza mediante el bloque de inicialización predeterminada (estática {}), pero Class.forName initialze (nombre, initialize, cargador) puede especificar si para ejecutar el bloque de inicialización.

Por ClassLoader.loadClass dinámicamente de carga () método no realiza bloque de inicialización.

Cargador de clases 9 encargo dos maneras

1, para cumplir modelo de los padres de la delegación: la herencia cargador de clases, reescribir método FindClass (). 2, socavan modelo de delegación parental: ClassLoader herencia, reescribir el método loadClass (). Por lo general se recomienda el primer método es un modelo de delegación cargador de clases a medida en los padres para cumplir con el máximo grado. Puesto que el propósito de definir el cargador de clases es la clase que desea cargar el control manual, y que, además de cargar manualmente la clase de esta manera, hay otras maneras por un cargador de clases a medida que?

Utilizar de cargador de clases existente para la carga:

1. El uso del cargador de clases actual

Class.forName();

2. El sistema de cargador de clases

Classloader.getSystemClassLoader().loadClass();

3. Por el cargador de clase de contexto

Thread.currentThread().getContextClassLoader().loadClass();

l URLClassLoader cargado usando:

URLClassLoader loader=new URLClassLoader(); loader.loadClass(); 

Demostración ejemplo cargador de clases: HelloWorld.java ejecutar la línea de comandos

public class HelloWorld{

 public static void main(String[] args){ System.out.println("Hello world"); } } 

Este código generalmente después de un poco pasos:

  • directorio jre que buscan encontrar jvm.dll, e inicializa la JVM.

  • Generación de un Bootstrap ClassLoader;

  • Bootstrap ClassLoader cargador se carga su ruta especificada núcleo java api y generar un cargador ClassLoader ejemplo extendido, a continuación, carga el extensiones Extended ClassLoader java api especificado trayectoria, y para establecer el padre Bootstrap ClassLoader.

  • generación de arranque ClassLoader Aplicación cargador de clases, y para configurar el cargador padres extendido cargador de clases.

  • Clase --HelloWorld definición de clase del directorio de ruta de clases última cargado por AppClass cargador de clases.

Hablamos de cargador de clases extendido arriba y Aplicación ClassLoader es creado por Launcher, y ahora nos fijamos en el código fuente:

 public Launcher() { Launcher.ExtClassLoader var1; try { //实例化ExtClassLoader var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { //实例化AppClassLoader this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } //主线程设置默认的Context ClassLoader为AppClassLoader. //因此在主线程中创建的子线程的Context ClassLoader 也是AppClassLoader Thread.currentThread().setContextClassLoader(this.loader); String var2 = System.getProperty("java.security.manager"); if(var2 != null) { SecurityManager var3 = null; if(!"".equals(var2) && !"default".equals(var2)) { try { var3 = (SecurityManager)this.loader.loadClass(var2).newInstance(); } catch (IllegalAccessException var5) { ; } catch (InstantiationException var6) { ; } catch (ClassNotFoundException var7) { ; } catch (ClassCastException var8) { ; } } else { var3 = new SecurityManager(); } if(var3 == null) { throw new InternalError("Could not create SecurityManager: " + var2); } System.setSecurityManager(var3); } } 

10 muy importante

Aquí también hay que prestar atención a varias cuestiones:
1. Sabemos cargador de clases para obtener una corriente binaria por el nombre completo de una clase, entonces si necesitamos un cargador de clase personalizada para cargarlo cuando un paquete tarro, es recorrer su propio tarro en la categoría, seguido de cargador de clases para cargarlo? o cómo cargar un paquete frasco que hacemos?
2. Si una referencia de clase de otras clases, a continuación, las otras clases cargadas por quién?
3. Puesto que la clase se puede hacer diferentes cargas de carga, la forma de determinar cómo dos clases son la misma clase?

A su vez Vamos a responder a estas dos preguntas: para los términos tarro de carga dinámica, JVM utiliza por defecto por primera vez para cargar el cargador de clases tarro de clase especificada como predeterminada ClassLoader Supongamos que exista Paquete frasco llamado sbbic ahora, esto. empaquetar existe clase a ni ClassB estas dos clases (no citados en claseA ClassB). ahora tenemos que cargar la clase ClassA por un ClassLoaderA costumbre, entonces el tiempo en este momento ClassLoaderA convertido sbbic.jar en otras clases cargador de clases por defecto es., es decir, ClassB también por defecto para cargar ClassLoaderA.

Así que si claseA ClassB referencia a ella? Cuando un cargador de clases cuando las cargas de claseA, ClassB encontraron referencias, esta vez se carga la clase si detecta ClassB no se ha cargado, y luego volver a la carga. Cuando la carga está completa ClassB, siguen regresando carga de ClassA. en otras palabras, la clase se cargaría correspondiente a la carga de otras clases referenciadas por sí mismo.

JVM establece que para cualquier clase, que tendrá que ser establecido por el cargador de clases de carga y clase en sí juntos en la máquina virtual de Java singularidad, punto popular es decir, se determina si la JVM dos clases son la misma clase depende archivos de clase generados con un objeto de clase en el cargador de clases y la clase en sí, que es el mismo cargador de clases a la carga es la misma, diferente cargador de clase, entonces las dos clases no son necesariamente los mismos.

Supongo que te gusta

Origin www.cnblogs.com/haojile/p/12578452.html
Recomendado
Clasificación