Hable sobre el ajuste del rendimiento de JVM todos los días, ¿conoce la arquitectura de JVM?

Prefacio:

Todos conocen la importancia de JVM en Java. Después de aprender JVM, comprenderá bien el mecanismo operativo de Java, el proceso de compilación y cómo ajustar los programas de Java. La JVM también es una parte muy importante de la entrevista, como el ajuste de la JVM, las reglas de asignación de objetos de la JVM, el modelo de memoria, el área de método y la GC.

Además, si desea responder a la entrevista, por favor haga clic en el 795983544 código secreto RDCC para obtener usted mismo. También he recogido más de 20 años de puntos de conocimiento de la entrevista compañía y varios puntos técnicos. Aquí hay algunas capturas de pantalla que espero que le ayude.
Inserte la descripción de la imagen aquí

No son muchas tonterías, solo llévate a todos a conocer la JVM.
Inserte la descripción de la imagen aquí

¿Qué es JVM?

JVM (Java Virtual Machine) es una computadora abstracta, como una computadora real, tiene un conjunto de instrucciones y utiliza diferentes áreas de almacenamiento, es responsable de ejecutar instrucciones y administrar datos, memoria y registros.

Al ver esto, las personas que pueden no entender JVM ya han quedado atrapadas. No importa, permítame presentarle el diagrama de arquitectura de JVM en detalle, tal vez lo entienda.

En términos simples, JVM es una computadora virtual. Todos sabemos que una de las características del lenguaje Java es multiplataforma, y ​​la JVM es una parte clave del programa Java para lograrlo. Cuando el compilador de Java compila un programa Java, genera códigos de bytes independientes de la plataforma (es decir, archivos .class) El llamado independiente de la plataforma significa que los códigos de bytes compilados están disponibles en sistemas Windows, Linux o Mac. llevado a cabo. Es decir, los archivos .class generados por la compilación de Java no están orientados a plataformas, sino a JVM. Las JVM en diferentes plataformas son diferentes, pero todas proporcionan la misma interfaz. La Figura 1 muestra los pasos generales de ejecución de Java:

Inserte la descripción de la imagen aquí
Citando un ejemplo mencionado en "Crazy Java Lectures" para ayudarlo a comprender el papel de JVM:

La función de JVM es como tener dos lápices diferentes, pero es necesario poner la misma tapa en dos bolígrafos diferentes.Solo se proporciona un convertidor para los dos bolígrafos.La interfaz ascendente de este convertidor es la misma para la adaptación. La misma tapa del bolígrafo; la interfaz hacia abajo es diferente, se utiliza para acomodar dos bolígrafos diferentes. En esta analogía, se puede entender a grandes rasgos que dos bolígrafos diferentes son sistemas operativos diferentes, y la misma tapa del bolígrafo es un programa de código de bytes de Java, y la función de convertidor corresponde a la JVM. De manera similar, la JVM también se puede considerar dividida en dos partes, hacia arriba y hacia abajo. Las JVM de todas las plataformas proporcionan las mismas interfaces para los programas de código de bytes de Java hacia arriba, pero las interfaces de las diferentes plataformas que se adaptan hacia abajo son diferentes entre sí.

Descripción general de la arquitectura JVM

Más arriba, tenemos una introducción preliminar a la función de la JVM, luego debemos comprender la comprensión profunda de la JVM de la arquitectura de la JVM, consulte la Figura 2: La
Inserte la descripción de la imagen aquí
Figura 2 es el diagrama de la arquitectura de la JVM, luego hablemos de cada uno juntos ¿Qué significan las partes?

1. Subsistema de cargador de clases (ClassLoader)

Responsable de cargar el archivo de clase, el archivo de clase tiene una marca de archivo específica al principio del archivo, carga el contenido del código de bytes del archivo de clase en la memoria y convierte el contenido en la estructura de datos en tiempo de ejecución en el área de métodos. El ClassLoader solo es responsable de la carga del archivo de clase En cuanto a si puede ejecutarse, lo determina el motor de ejecución.

Los archivos * .class generados por la compilación de Java se cargan a través de ClassLoader, por lo que hay varios problemas aquí:

¿Cómo sabe ClassLoader que el archivo * .class es el archivo que se va a cargar?
Si cambio manualmente el nombre de extensión de un archivo normal al sufijo de clase, ¿ClassLoader cargará el archivo?
De hecho, el archivo de clase tiene un identificador de archivo específico al principio del archivo. Simplemente escriba un programa Java y compile un archivo de clase. Después de abrirlo, puede ver lo siguiente:
Inserte la descripción de la imagen aquí
cafe babe es un identificador del archivo de clase y ClassLoader es responsable Carga el archivo de clase con cafe babe, carga el contenido del código de bytes del archivo de clase en la memoria y convierte el contenido en la estructura de datos en tiempo de ejecución en el área de métodos. El ClassLoader solo es responsable de cargar el archivo de clase, en cuanto a si se puede ejecutar , Lo determina el motor de ejecución, consulte la Figura 3:
Inserte la descripción de la imagen aquí
ClassLoader carga el archivo Car.class en la memoria, Car Class es equivalente a una plantilla en la memoria, podemos instanciar diferentes instancias car1, car2, car3 a través de esta plantilla .

Me pregunto si tiene alguna pregunta, ¿qué tipo de cargador se utiliza para cargar Car.class en Java por ClassLoader? Antes de responder a esta pregunta, escribamos un código simple para ver:

//new一个Car对象
        Car car = new Car();

        //得到ClassLoader
        ClassLoader classLoader = car.getClass().getClassLoader();

        //打印结果
        System.out.println(classLoader);

Inserte la descripción de la imagen aquí
El resultado:
echemos un vistazo a otro conjunto de códigos:

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">        //new两个不同的对象
        Car car = new Car();
        String string = new String(); //得到ClassLoader
        ClassLoader classLoader1 = car.getClass().getClassLoader();
        ClassLoader classLoader2 = string.getClass().getClassLoader(); //打印结果
 System.out.println(classLoader1);
        System.out.println(classLoader2);</pre>

El resultado es:
Inserte la descripción de la imagen aquí
de lo anterior, podemos saber que uno de los resultados de impresión de ClassLoader es "sun.misc.Launcher$AppClassLoader@18b4aac2" y el otro es "nulo". Cuál es el problema, amigos cuidadosos pueden encontrar estos dos Entre los diferentes objetos, el objeto car es una clase escrita por nosotros mismos, y el objeto string es una clase que viene con el sistema. En pocas palabras, ClassLoader seleccionará diferentes cargadores de clases para cargar según las diferentes clases. Esto implica la clasificación de ClassLoader

Categoría ClassLoader:

Bootstrap (BootStrap),
cargador de clases de extensión (Extension),
cargador de clases de aplicaciones (AppClassLoader),
cargador definido por el usuario,
generalmente el cargador de clases que escribimos nosotros mismos es AppClassLoader, que se muestra en la figura anterior. sun.misc.Launcher$AppClassLoader@18b4aac2 ", y ¿por qué la cadena del objeto es" nula "? De hecho, este "nulo" se refiere al uso de BootStrap, el cargador.

Algunas personas pueden tener preguntas. La clase definida por usted mismo usa AppClassLoader, que se puede entender, porque el nombre de la salida del cargador de clases del objeto car tiene la palabra AppClassLoader, pero por qué la cadena del objeto es "nula" y dónde se puede usar es BootStrap. ¿Y el cargador? Este es el caso. El cargador acumulativo de BootStrap es equivalente al antepasado del cargador de clases extendido y del cargador de clases de aplicaciones. Si se utiliza BootStrap, el nivel superior de BootStrap ya no está disponible, por lo que se representa mediante "nulo"

De hecho, podemos encontrar la ubicación de la clase String en el JDK:

$JAVA_HOME/jre/lib/rt.jar/java/lang

Todas las clases del paquete jar de $ JAVA_HOME / jre / lib / rt.jar en esta ruta se cargan con BootStrap.

Consulte la Figura 4 a continuación:
Inserte la descripción de la imagen aquí
Esta imagen se puede ver claramente:

1. Todo en $ Java_Home / jre / lib / rt.jar se carga a través de BootStrap

2. Todo en $ Java_Home / jre / lib / ext / *. Jar se carga a través de la extensión

3. Todo en $ CLASSPATH se carga a través del SISTEMA (el cargador de clases de aplicaciones también se denomina cargador de clases del sistema, que carga todas las clases de la ruta de clases de la aplicación actual)

A continuación, miramos un ejemplo:

¿Qué pasa si crea un paquete java.lang, luego crea una clase String, imprime una oración y la ejecuta?

<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; word-wrap: break-word; font-family: &quot;Courier New&quot; !important; font-size: 12px !important;">package java.lang; public class String {
    
     public static void main(String[] args) {
    
    
        System.out.println("Hello World");
    }
}</pre>

El efecto es el siguiente:
Inserte la descripción de la imagen aquí
puede ver que el programa informa de un error, diciendo que no se puede encontrar el método principal, pero ¿por qué no se ejecuta cuando hay un método principal? Esto involucra el mecanismo de delegación principal

Mecanismo de delegación de padres:

Cuando una clase recibe una solicitud de carga de clases, no intentará cargar la clase por sí mismo primero, sino que delegará la solicitud a la clase principal para completarla. Este es el caso de todos los cargadores de clases jerárquicos, por lo que todas las solicitudes de carga deben enviarse En el cargador de clases de inicio, solo cuando el cargador de clases principal informa que no puede completar la solicitud (la clase que se va a cargar no se encuentra en su ruta de carga), el cargador de clases secundario intentará cargarla por sí mismo.

Entonces, su proceso de ejecución real es así:

ClassLoader recibió una solicitud para cargar la clase String.
Primero vaya a Bootstrap para encontrar si hay esta clase. Si no hay comentarios, la solicitud no se puede completar. Sin embargo, sucede que la clase java.lang.Stirng se encuentra en rt.jar para
ejecutar esta clase. Esta clase es un
informe de error que no define el método principal . El método principal no
está definido, por lo que en el ejemplo anterior, encontrará la clase java.lang.String en el jdk. Esta clase no define el método principal. En pocas palabras, la clase que ejecuta es la clase java.lang.String en el JDK. No es una clase definida por nosotros mismos.

¿Cuáles son las ventajas de utilizar el mecanismo de delegación principal?

Una ventaja de usar la delegación principal es que, por ejemplo, al cargar la clase java.lang.Object ubicada en el paquete rt.jar, sin importar qué cargador cargue esta clase, finalmente se delegará en el cargador de clases de inicio de nivel superior para su carga, a fin de garantizar El resultado final de utilizar diferentes cargadores de clases es el mismo objeto Object.

2. Motor de ejecución

El motor de ejecución se encarga de interpretar los comandos y enviarlos al sistema operativo para su ejecución, el motor de ejecución no se explicará demasiado aquí, siempre y cuando sepa que es el responsable de interpretar los comandos.

3. Interfaz nativa y pila de métodos nativos

Interfaz nativa: La función de la interfaz nativa es integrar diferentes lenguajes de programación para Java. Su intención original es integrar programas C / C ++. Cuando nació Java, cuando C / C ++ estaba desenfrenado, si quieres ganar terreno, debes llamar a los programas C / C ++. , Entonces se abre un área especial en la memoria para procesar el código marcado como nativo, su método específico es registrar el método nativo en la pila de métodos nativos y cargar las librerías nativas cuando se ejecuta el motor de ejecución.
En la actualidad, este método se usa cada vez menos, excepto para aplicaciones relacionadas con el hardware, como manejar impresoras a través de programas Java o administrar equipos de producción a través de sistemas Java, que son relativamente raros en aplicaciones de nivel empresarial. Debido a que la comunicación entre dominios heterogéneos ahora está muy desarrollada, por ejemplo, puede usar la comunicación Socket, también puede usar Web Service, etc., sin mucha introducción.

Si ve la palabra clave nativa en el programa, significa que no es algo que Java pueda hacer, y necesita cargar la biblioteca de métodos local para completar

Pila de métodos locales : su método específico es registrar el método nativo en la pila de métodos nativos y cargar la biblioteca de métodos locales cuando se ejecuta el motor de ejecución. Para decirlo sin rodeos, los métodos locales son registrados por la pila de métodos locales, y los métodos en Java son registrados por la pila de Java.

4.Registro de PC (registro de contador de programa)

Cada subproceso tiene un contador de programa, que es privado para el subproceso, es decir, un puntero al código de byte del método en el área de método (utilizado para almacenar la dirección de la siguiente instrucción, que es el código de instrucción a ejecutar), que es ejecutado por el motor de ejecución. Leer la siguiente instrucción es un espacio de memoria muy pequeño, casi insignificante.
Esta área de memoria es muy pequeña, es el indicador de número de línea del bytecode ejecutado por el hilo actual, el intérprete de bytecode selecciona la siguiente instrucción de bytecode a ejecutar cambiando el valor de este contador.
Si la ejecución es un método nativo, entonces este contador está vacío.
El registro de la PC se utiliza para completar funciones básicas como bifurcaciones, bucles, saltos, manejo de excepciones y recuperación de subprocesos. Dado que la memoria utilizada es pequeña, no habrá ningún error de OutOfMemory.

Al final

Entonces, este artículo se detendrá aquí primero, y en el próximo artículo continuaremos hablando sobre el área de método, pila y montón ...

Además, si desea responder a la entrevista, por favor haga clic en el 795983544 código secreto RDCC para obtener usted mismo. También he recogido más de 20 años de puntos de conocimiento de la entrevista compañía y varios puntos técnicos. Aquí hay algunas capturas de pantalla que espero que le ayude.
Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_50524970/article/details/108762621
Recomendado
Clasificación