¿Cuál es el principio de JVM?
En primer lugar, aclaremos dos conceptos aquí: la instancia JVM y la instancia del motor de ejecución JVM. La instancia JVM corresponde a un programa Java que se ejecuta de forma independiente, mientras que la instancia del motor de ejecución JVM corresponde al hilo que pertenece al programa que ejecuta el usuario. ; es decir, la instancia de JVM está en el nivel de proceso, mientras que el motor de ejecución está en el nivel de subproceso. ¿Qué es la JVM? —Ciclo de vida de JVM El nacimiento de una instancia de JVM: cuando se inicia un programa Java, se genera una instancia de JVM. Cualquier clase con una función publicstaticvoidmain(String[]args) se puede utilizar como punto de partida para que se ejecute la instancia de JVM. En este caso, ¿cómo sabe la JVM que está ejecutando el sistema principal de clase A en lugar del principal de clase B? Esto requiere decir explícitamente el nombre de la clase JVM, que es el origen de los comandos que normalmente ejecutamos en los programas Java, como JavaclassAhelloworld, donde Java le dice al sistema operativo que ejecute la máquina virtual Java de SunJava2SDK, y la claseA indica el nombre de clase requerido para ejecutar la JVM. Ejecución de una instancia de JVM: main() sirve como punto de partida del subproceso inicial del programa, y cualquier otro subproceso se inicia mediante este subproceso. Hay dos tipos de subprocesos dentro de la JVM: subprocesos de demonio y subprocesos que no son de demonio. main() es un subproceso que no es de demonio y que generalmente utilizan los propios programas Java que también pueden marcar los subprocesos que crean como subprocesos de demonio. . Muerte de la instancia de JVM: la JVM se cierra cuando finalizan todos los subprocesos que no son demonios del programa; si el administrador de seguridad lo permite, el programa también puede usar la clase Runtime o System.exit() para salir. ¿Qué es la JVM? —La arquitectura de la JVM se puede dividir aproximadamente en tres partes: el subsistema del cargador de clases (ClassLoader), el área de datos de tiempo de ejecución y el motor de ejecución. A continuación se presentará primero el cargador de clases, luego el motor de ejecución y finalmente el área de datos de tiempo de ejecución 1. El cargador de clases, como su nombre indica, se utiliza para cargar archivos .class. Los dos tipos de cargadores de clases de JVM incluyen: cargador de clases de inicio y cargador de clases definido por el usuario. El cargador de clases de inicio es parte de la implementación de JVM, y el cargador de clases definido por el usuario es parte del programa Java y debe ser una subclase. de la clase Cargador de clases. (La situación que se describe a continuación es para SunJDK1.2) Cargador de clases dinámico: solo busque la clase que se cargará en la ruta de instalación de la clase del sistema (archivo de clase JavaAPI) Cargador de clases definido por el usuario: Cargador de clases del sistema: comience en la JVM creada en ese momento, se utiliza para encontrar la clase que se cargará en el directorio CLASSPATH. Otros cargadores de clases definidos por el usuario: primero es necesario hablar sobre varios métodos de la clase ClassLoader. Comprenderlos es esencial para comprender cómo se carga el cargador de clases personalizado. Archivos .class cruciales. protectedfinalClassdefineClass(Stringname, bytedata[], intoffset, intlength) protectedfinalClassdefineClass(Stringname, bytedata[], intoffset, intlength, ProtectionDomainprotectionDomain); protectedfinalClassfindSystemClass(Stringname) protectedfinalvoidresolveClass(Classc) defineClass se utiliza para importar archivos de clases binarias (nuevos tipos) al método. area, es decir, la clase a la que se hace referencia aquí es una clase definida por el usuario (es decir, responsable de cargar la clase). findSystemClass usa el nombre completo del tipo, primero lo carga a través del cargador de clases del sistema o del cargador de clases de inicio, y devuelve el objeto Clase.
ResolveClass: permite que el cargador de clases realice acciones de conexión (incluida la verificación, la asignación de inicialización de memoria y la resolución de referencias de símbolos en tipos en referencias directas). Esto implica la cuestión del espacio de nombres de Java. La garantía de que la JVM será referenciada por una clase cargada por un. Cargador de clases. Todas las clases son cargadas por este cargador de clases. Las clases cargadas por el mismo cargador de clases pueden acceder entre sí, pero las clases cargadas por diferentes cargadores de clases no pueden verse entre sí, logrando así un blindaje efectivo. 2. Motor de ejecución: ejecuta código de bytes o ejecuta métodos locales. En términos de motor de ejecución, debe tener un conjunto de instrucciones. Cada instrucción contiene un código de operación de un solo byte, seguido de 0 o más operandos. (1) El conjunto de instrucciones está diseñado con la pila como centro en lugar del registro como centro. ¿Cómo cumple este diseño de conjunto de instrucciones con los requisitos del sistema Java? Independencia de plataforma: la pila como centro hace que sea más conveniente de implementar. Java en máquinas con pocos registros. El compilador generalmente usa la pila para transferir los resultados intermedios de la compilación al optimizador de conexión. Si el conjunto de instrucciones se basa en la pila, es beneficioso combinar el trabajo de optimización realizado en tiempo de ejecución con el motor de ejecución. que realiza una compilación justo a tiempo u optimización adaptativa. En términos sencillos, significa que la unificación del compilador con la estructura de datos utilizada para la operación es más propicia para la optimización. Movilidad de red: compacidad de los archivos de clase. Seguridad: la mayoría de los códigos de operación en el conjunto de instrucciones especifican el tipo de operación. (Usar el período de análisis del flujo de datos para una verificación única durante la carga, en lugar de la verificación cuando se ejecuta cada instrucción, ayudará a mejorar la velocidad de ejecución). (2) Tecnología de ejecución Las principales tecnologías de ejecución incluyen: interpretación, compilación justo a tiempo, optimización adaptativa y ejecución directa a nivel de chip. La interpretación pertenece a la JVM de primera generación y la compilación justo a tiempo JIT pertenece a la segunda generación. JVM y optimización adaptativa (actualmente utilizada por Hotspot JVM de Sun). Esta tecnología se basa en la experiencia de la JVM de primera generación y la JVM de segunda generación, y utiliza una combinación de las dos para optimizar de forma adaptativa: comience interpretando y ejecutando todos los códigos. y monitorear la ejecución del código, y luego optimizar aquellos que con frecuencia. El método llamado inicia un hilo en segundo plano, lo compila en código nativo y lo optimiza cuidadosamente. Si el método ya no se usa con frecuencia, el código compilado se cancelará y aún se interpretará y ejecutará. 3. Área de datos en tiempo de ejecución: incluye principalmente: área de métodos, montón, pila de Java, registro de PC, pila de métodos locales (1) El área de métodos y el montón son compartidos por todos los subprocesos: almacena todos los métodos de objetos creados por el programa en tiempo de ejecución. : Cuando el cargador de clases JVM carga el archivo .class, lo analiza y coloca la información del tipo analizado en el área de método. (2) La pila de Java y el registro de PC son exclusivos de los subprocesos durante el tiempo de creación de un nuevo subproceso (3) Pila de métodos locales: almacena el estado de las llamadas a métodos locales. El contenido principal del área de datos de tiempo de ejecución se presenta generalmente arriba. La siguiente es una introducción detallada. Para presentar el área de datos, tenemos que explicar los tipos de datos en la JVM. Tipos de datos en JVM: la unidad de datos básica en JVM es la palabra, y la longitud de la palabra la determina el implementador específico de JVM. Los tipos de datos incluyen tipos básicos y tipos de referencia (1) Los tipos básicos incluyen: tipos numéricos (incluidos excepto booleanos). ) Todos los tipos de datos básicos de Java), booleano (representado por int en la JVM, 0 representa falso y otros valores int representan verdadero) y returnAddress (el tipo interno de la JVM, utilizado para implementar la cláusula finalmente).
(2) Los tipos de referencia incluyen: tipos de matriz, tipos de clase y tipos de interfaz. La sección anterior describe la representación de datos en la JVM. Ingresemos el área de datos en la JVM y primero veamos el área de métodos: como se mencionó anteriormente, el área de método se utiliza principalmente para el almacenamiento. La JVM extrae información de tipo de archivos de clase, entonces, ¿cómo se almacena la información de tipo? Como todos sabemos, Java usa big-endian (big?endian): los datos de bytes bajos se almacenan en la memoria de bytes altos. Por ejemplo, para 1234, 12 son datos de bytes altos y 34 son datos de bytes bajos, entonces. El formato de almacenamiento en Java debe ser 12. La dirección baja de la memoria, 34 existe en la dirección alta de la memoria, el formato de almacenamiento en x86 es opuesto) para almacenar datos. Este es en realidad el formato de almacenamiento de los datos en el archivo de clase. , pero cuando los datos se vierten en el área del método, la JVM se puede almacenar de cualquier forma. Información de tipo: incluido el nombre completo de la clase, la clase principal directa de la clase, el tipo de clase o el tipo de interfaz, el modificador de la clase (pública, etc.), la lista de todas las interfaces principales directas, la clase El objeto proporciona una ventana para acceder a esta información (se puede obtener a través de Class.forName ("") o instancia.getClass ()), los siguientes son los métodos de Class, creo que todos lo entenderán de repente después de leerlo, (eso es todo) getName (), getSuperClass(), isInterface(), getInterfaces(), getClassLoader(); la variable estática guarda la referencia a la clase ClassLoader como parte de la información de tipo: otras clases a las que se hace referencia en la clase se cargan durante la conexión dinámica. la clase Class: inevitablemente, el grupo de constantes de este tipo se ha descrito anteriormente: incluye constantes directas (constantes de cadena, enteras y de punto flotante) y referencias simbólicas a otros tipos, campos y métodos (nota: el grupo de constantes aquí no es un lugar para almacenar constantes en el sentido ordinario. Estas referencias simbólicas pueden ser con las que entramos en contacto en la programación), debido a estas referencias simbólicas, el grupo de constantes se ha convertido en una parte crucial de la conexión dinámica de los programas Java. información del método declarada en el tipo en un sentido común: información sobre cada método en el tipo Constantes de tiempo de compilación: se refiere a Una variable de clase declarada final o inicializada con un valor conocido en el momento de la compilación copia todas las constantes a su grupo de constantes o su código de bytes. arroyo. Tabla de métodos: una matriz que contiene referencias directas a todos los métodos de instancia que sus instancias pueden llamar (incluidos los heredados de las clases principales). Además, si una clase no es abstracta y local, también almacena los literales del código de la sección. , pila de operandos y marco de pila del método, tabla de excepciones. Ejemplo: classLava{ privateintspeed=5; voidflow(){} classVolcano{ publicstaticvoidmain(String[]args){ Lavalava=newLava(); lava.flow() } } Ejecute el comando JavaVolcano (1) JVM encuentra Volcano.class; Ingrese y extraiga la información del tipo correspondiente al área de método. Al ejecutar el código de bytes en el área de métodos, la JVM ejecuta el método main() (el puntero al grupo constante de la clase Vocano siempre se guardará durante la ejecución) (2) La primera instrucción en Main() le dice a la JVM que debe ser una constante enumerada en La clase del primer elemento del grupo asigna memoria (aquí nuevamente se explica que el grupo constante no solo almacena información constante), luego la JVM encuentra el primer elemento del grupo constante y encuentra que es una referencia simbólica a la clase Lava, luego verifica el área del método para ver si la clase Lava se carga, y el resultado es que no se ha cargado, luego busca "Lava.class", escribe la información del tipo en el área de método y reemplace la referencia de símbolo en el grupo constante original de Volcano con el puntero a la información de la clase Lava en el área de método, es decir, use una referencia directa.
(3) La JVM ve la nueva palabra clave y se prepara para asignar memoria para Lava. Encuentra la ubicación de Lava en el área del método de acuerdo con el primer elemento del grupo constante de Volcano y analiza cuántos pares de espacio se necesitan. asigne espacio en el montón, inicialice la variable de velocidad en 0 y coloque la referencia del objeto de lava en la pila (4) Llame al método flow() de lava. Ahora que tenemos una comprensión general del contenido del área del método. , echemos un vistazo a la implementación del montón del objeto Java del montón: los objetos Java se componen principalmente de variables de instancia (incluidas las declaradas por la clase a la que pertenecen y sus clases principales), punteros a datos de clase en el área de métodos. , punteros a tablas de métodos, bloqueos de objetos (no necesarios) y colecciones de espera (no necesarios, datos relacionados con GC (no necesarios) (depende principalmente del algoritmo de GC. Por ejemplo, para los algoritmos de marca y borrado, es necesario). marque si se hace referencia al objeto y si se ha llamado al método finalize()). Entonces, ¿por qué los objetos Java necesitan punteros a datos de clase? Considerémoslo desde varios aspectos: primero: cuando una referencia de objeto se convierte a otro tipo en el programa, ¿cómo verificar si la conversión está permitida? Se necesitan datos de clase. En segundo lugar: cuando se vincula dinámicamente, no se necesita un tipo de referencia, sino un tipo de tiempo de ejecución. La confusión aquí es: ¿por qué se almacena el tipo real en los datos de la clase en lugar del tipo de referencia? Dejaré esta pregunta por ahora. Creo que debería poder entender el puntero a la tabla de métodos en las notas de lectura siguientes: esto es similar al VTBL de C, que es beneficioso para mejorar la eficiencia de las llamadas a métodos: usado. para implementar múltiples pares de subprocesos* Conjunto de espera de acceso mutuamente excluyente para datos compartidos: se utiliza para permitir que múltiples subprocesos coordinen sus esfuerzos para lograr el mismo objetivo. (Tenga en cuenta los métodos wait(), notify(), notifyAll() en la clase Object). Implementación de montón de matrices de Java: las matrices también tienen una instancia de clase asociada con su clase. Las matrices con la misma dimensión y tipo son instancias de la misma clase. Representación del nombre de la clase de matriz: por ejemplo, [[LJava/lang/Object representa Object[][], [I representa int[], [[[B representa byte[][][]). Se ha introducido aproximadamente. Sigamos presentando el contador de programa y el contador de programa de pila Java: único para cada hilo, creado cuando se inicia el hilo. Si el hilo ejecuta un método Java, la PC guarda la dirección de la siguiente instrucción de ejecución. Si el subproceso ejecuta el método nativo, el valor de Pc no está definido. Pila de Java: la pila de Java guarda el estado de ejecución del subproceso en unidades de fotogramas. La pila de Java tiene solo dos operaciones: empujar y hacer estallar fotogramas. Cada marco representa un método. Los métodos Java tienen dos métodos de retorno, devolver y lanzar excepciones. Ambos métodos harán que el marco correspondiente al método salga de la pila y libere memoria. La composición del marco: área de variables locales (incluidos los parámetros del método y las variables locales. Para el método de instancia, este tipo debe guardarse primero, en el cual los parámetros del método se colocan estrictamente en el orden de declaración y las variables locales se pueden colocar arbitrariamente ), pila de operandos, área de datos del marco (se utiliza para ayudar a admitir el análisis constante del grupo, retornos de métodos normales y manejo de excepciones). Pila de métodos locales: depende de la implementación de los métodos locales. Por ejemplo, la interfaz del método local implementada por una determinada JVM utiliza el modelo de conexión C, entonces la pila de métodos locales es la pila C. Se puede decir que cuando un hilo llama a un. método local, ingresa a un hilo que no se ve afectado por las áreas restringidas de JVM, es decir, la JVM puede usar métodos nativos para extenderse dinámicamente. Creo que todos entienden qué es JVM. Enlace original: blogs.com/chenzhao/archive/2011/08/14/2137713.html