1 descripción general
Se sabe que Java es compatible con la plataforma Agnóstica, la seguridad y la movilidad de la red. La plataforma Java está compuesta por Java Virtual Machines y Java Core Classes, que proporciona una interfaz de programación unificada para programas Java puros, independientemente del sistema operativo más bajo. Se debe precisamente a la máquina virtual Java que su afirmación de ser "compilado una vez, ejecutar en todas partes" puede garantizarse.
1.1 Proceso de ejecución del programa Java
La ejecución de los programas Java depende del entorno de compilación y el entorno de ejecución. El código fuente se convierte en el código de máquina ejecutable, que se completa con el siguiente proceso:
El núcleo de la tecnología Java es la máquina virtual Java, porque todos los programas Java se ejecutan en la máquina virtual. El funcionamiento de los programas Java requiere la cooperación de Java Virtual Machine, Java API y archivos de clase Java. La instancia de la máquina virtual Java es responsable de ejecutar un programa Java. Cuando se inicia un programa Java, nace una instancia de máquina virtual. Cuando finaliza el programa, la instancia de la máquina virtual muere.
La función multiplataforma de Java se debe a que tiene máquinas virtuales dirigidas a diferentes plataformas.
1.2 Máquina virtual Java
La tarea principal de una máquina virtual Java es cargar archivos de clase y ejecutar los bytecodes en el mismo. Como se puede ver en la figura a continuación, la máquina virtual Java contiene un cargador de clase, que puede cargar archivos de clase de programas y API. Solo las clases requeridas para la ejecución del programa se cargarán en la API Java, y el motor de ejecución ejecuta el Bytecode.
Cuando un software implementa una máquina virtual Java en el sistema operativo host, el programa Java interactúa con el host llamando a métodos locales. Los métodos Java se escriben en lenguaje Java, se compilan en Bytecode y se almacenan en archivos de clase. El método local está escrito en el lenguaje C/C ++/ensamblaje, compilado en el código de máquina relacionado con el procesador, almacenado en la biblioteca de enlaces dinámicos y el formato es propietario de cada plataforma. Por lo tanto, el método local es conectar los programas Java al sistema operativo de host subyacente.
Dado que la máquina virtual Java no sabe cómo se creó un archivo de clase y si fue manipulado, implementa un detector de archivos de clase para garantizar que los tipos definidos en el archivo de clase se puedan usar de manera segura. El verificador de archivos de clase garantiza la robustez del programa a través de cuatro escaneos independientes:
・ Colección de archivo de clase
・ Comprobación semántica de datos de tipo
・ Verificación del código de byto
・ Verificación de referencia de símbolos
Al ejecutar ByTecode, Java Virtual Machines también realiza otros mecanismos de seguridad incorporados. Son las características de garantizar la robustez de los programas Java como lenguajes de programación Java, y también son las características de las máquinas virtuales Java:
・ Conversión de referencia segura
・ Acceso a la memoria estructurada
・ Recolección de basura automática
・ Verificación de límite de matriz
・ Comprobación de cotización vacía
1.3 Tipo de datos de máquina virtual Java
Las máquinas virtuales Java realizan cálculos a través de ciertos tipos de datos. Los tipos de datos se pueden dividir en dos tipos: tipos básicos y tipos de referencia, como se muestra en la figura a continuación:
Pero Boolean es un poco especial. Cuando el compilador compila el código fuente de Java en Bytecode, representará booleano con int o byte. En Java Virtual Machines, False está representado por 0, y True está representado por todos los enteros distintos de cero. Al igual que el lenguaje Java, el rango de valor del tipo básico de una máquina virtual Java es consistente en todas partes, sin importar cuál sea la plataforma de host, un largo siempre es un entero firmado con un complemento de 64 bits dos en cualquier máquina virtual.
Para ReturnAddress, este tipo básico se utiliza para implementar la cláusula Finalmente en un programa Java. Los programadores de Java no pueden usar este tipo, su valor apunta al código de operación de una instrucción de máquina virtual.
2architectura
En la especificación de la máquina virtual Java, el comportamiento de una instancia de máquina virtual se describe en términos de subsistema, área de memoria, tipo de datos e instrucciones, y estos componentes juntos muestran la arquitectura interna de máquina virtual abstracta.
2.1 archivo de clase
El archivo JavaClass contiene toda la información sobre una clase o interfaz. El "tipo base" del archivo de clase es el siguiente:
| U1 | 1 byte, tipo sin firmar |
| U2 | 2 bytes, tipo sin firmar |
| U4 | 4 bytes, tipo sin firmar |
| U8 | 8 bytes, tipo sin firmar |
Si desea saber más, el JVM SE7 de Oracle da la especificación oficial: la especificación de máquina virtual Java®
El contenido del archivo de clase:
Classfile {U4 Magic; // Número mágico: 0xCafebabe, utilizado para determinar si es un archivo de clase Java U2 minor_version; // Número de versión menor U2 Major_version; // Número de versión principal U2 constant_pool_count; // tamaño constante de la piscina cp_info constant_pool [constant_pool_count-1]; // Pool constante U2 Access_Flags; // Acceda a los indicadores en los niveles de clase e interfaz (obtenidos a través de | operación) U2 this_class; // índice de clase (apuntando a constantes de clase en el grupo constante) U2 super_class; // índice de clase actual (apuntando a constantes de clase en el grupo constante) U2 interfaces_count; // Interfaces Index Counter U2 Interfaces [interfaces_count]; // Interface Index Set U2 Fields_Count; // Field Count Count Field_info Fields [Fields_Count]; // Tabla de campo Conjunto de métodos U2_Count; // Métodos contador de métodos Métodos [Methods_Count]; // Método Tabla Establecer Atributes U2_Count; // Número de atributos atribuidos_info atributos [atributes_count]; // tabla de atributos} 2.2 Subsistema de cargador de clase
El subsistema de cargadores de clase es responsable de encontrar y cargar información de tipo. De hecho, hay dos tipos de cargadores para máquinas virtuales Java: cargadores del sistema y cargadores definidos por el usuario. El primero es parte de la implementación de la máquina virtual Java, mientras que el segundo es parte del programa Java.
・ BootstrapClassLoader: se utiliza para cargar la biblioteca central de Java, implementada en código nativo y no se hereda de java.lang.classloader.
・ ExtensionClassLoader: se utiliza para cargar bibliotecas de extensión Java. La implementación de la máquina virtual Java proporcionará un directorio de biblioteca de extensión. Este cargador de clase busca y carga las clases de Java en este directorio.
・ Cargador de clase de aplicación: Carga las clases de Java de acuerdo con el ClassPath de la aplicación Java (classPath). En términos generales, las clases de aplicación Java están cargadas por ello. Se puede obtener a través de classloader.getSystemClassLoader ().
Además de los cargadores de clase proporcionados por el sistema, los desarrolladores pueden implementar sus propios cargadores de clase heredando la clase Java.Lang.ClassLoader para satisfacer algunas necesidades especiales.
El subsistema de cargadores de clase involucra varios otros componentes de la máquina virtual Java y las clases de la biblioteca Java.Lang. El método definido por ClassLoader proporciona una interfaz para que el programa acceda al mecanismo del cargador de clases. Además, para cada tipo que se carga, la máquina virtual Java crea una instancia de la clase Java.Lang.Class para representar el tipo. Al igual que otros objetos, los cargadores de clase definidos por el usuario y las instancias de clase se colocan en el área del montón de la memoria, mientras que la información de tipo cargada se encuentra en el área del método.
Además de localizar e importar archivos de clase binaria, el subsistema de cargadores de clase también debe ser responsable de verificar la corrección de la clase importada, asignar e inicializar la memoria para las variables de clase y las referencias simbólicas de análisis. Estas acciones también deben realizarse en el siguiente orden:
・ Cargar (encontrar y cargar datos binarios de tipo)
・ Conexión (Verificación de ejecución: Asegúrese de la corrección del tipo importado; Preparación: asignar memoria para las variables de clase e inicializarlos a valores predeterminados; análisis: convertir referencias simbólicas en el tipo en referencias directas)
・ Inicialización (las variables de clase se inicializan al valor inicial correcto)
2.3 Área de método
En una máquina virtual Java, la información sobre el tipo cargada se almacena en la memoria en un área de método. Cuando una máquina virtual carga cierto tipo, utiliza un cargador de clase para ubicar el archivo de clase correspondiente, luego lee el archivo de clase y lo transfiere a la máquina virtual. Luego, la máquina virtual extrae la información de tipo y almacena esta información en el área del método. Las áreas de método también pueden ser recolectadas por el recolector de basura, porque la máquina virtual permite la extensión dinámica de los programas Java a través de cargadores de clase definidos por el usuario.
La siguiente información se almacena en el área del método:
・ Este tipo de nombre totalmente calificado (como el nombre totalmente calificado java.lang.object)
・ El nombre totalmente calificado de este tipo de superclase directo
・ ¿Es este tipo de clase de tipo o tipo de interfaz?
・ Este tipo de modificador de acceso (un subconjunto de público, resumen, final)
・ Lista ordenada de nombres totalmente calificados para cualquier hiperinterface directo
・ Punato constante de este tipo (una colección ordenada que incluye constantes directas [String, Integer y FloatingPoint Constants] y referencias simbólicas a otros tipos, campos y métodos)
・ Información de campo (nombre de campo, tipo, modificador)
・ Información del método (nombre del método, tipo de retorno, número de parámetros y tipo, modificador)
・ Todas las variables de clase (estática) excepto constantes
・ Referencia a la clase ClassLoader (cuando se carga cada tipo, la máquina virtual debe rastrear si está cargada por el cargador de clase de inicio o el cargador de clase definido por el usuario)
・ Referencia a la clase de clase (para cada tipo que se carga, la máquina virtual creará una instancia de la clase java.lang.class en consecuencia. Por ejemplo, si tiene una referencia al objeto de la clase java.lang.integer, entonces solo necesita llamar al método getClass () referenciado por el objeto entero para obtener el objeto de clase que representa la clase java.integer)
2.4 montón
Todas las instancias de clase o matrices creadas por los programas Java en tiempo de ejecución (las matrices son un objeto real en una máquina virtual Java) se colocan en el mismo montón. Dado que las instancias de la máquina virtual Java solo tienen un espacio de montón, todos los hilos compartirán este montón. Cabe señalar que la máquina virtual Java tiene una instrucción para asignar objetos en el montón, pero no tiene una instrucción para liberar la memoria, porque la máquina virtual entregó esta tarea al recolector de basura para su procesamiento. La especificación de la máquina virtual Java no hace cumplir los recolectores de basura, solo requiere que las implementaciones de la máquina virtual deben administrar su propio espacio de montón "de alguna manera". Por ejemplo, una implementación solo puede tener un espacio de montón de tamaño fijo. Cuando se llena el espacio, simplemente arroja una excepción de Mememoria, que no considera el problema del reciclaje de objetos de basura, pero cumple con las especificaciones.
La especificación de la máquina virtual Java no especifica cómo se representan los objetos Java en el montón, lo que le da al implementador de las decisiones de la máquina virtual sobre cómo diseñar. Un posible diseño de montón es el siguiente:
Una piscina de mango, una piscina de objetos. La referencia de un objeto es un puntero local para el grupo de identificadores. Los beneficios de este diseño conducen a la clasificación de fragmentos de montón. Al mover objetos en el grupo de objetos, la parte del mango solo necesita cambiar la nueva dirección del puntero que apunta al objeto. La desventaja es que cada vez que se accede a una variable de instancia de un objeto, debe pasar a través de dos punteros.
2.5 pila de java
Cada vez que se inicia un hilo, la máquina virtual Java le asigna una pila Java. Una pila Java consta de muchos marcos de pila, un marco de pila contiene el estado de una llamada de método Java. Cuando un hilo llama a un método Java, la máquina virtual empuja un nuevo marco de pila en la pila Java del hilo. Cuando el método regresa, el marco de la pila aparece desde la pila Java. La pila Java almacena el estado de las llamadas del método Java en los subprocesos, incluidas las variables locales, los parámetros, los valores de retorno y los resultados intermedios de las operaciones, etc. Las máquinas virtuales Java no tienen registros, y su conjunto de instrucciones utiliza una pila Java para almacenar datos intermedios. La razón de este diseño es mantener el conjunto de instrucciones de la máquina virtual Java lo más compacta posible, y también facilitar la implementación de la máquina virtual Java en una plataforma con pocos registros generales. Además, la arquitectura basada en la pila también ayuda a optimizar el código de compiladores dinámicos y compiladores instantáneos implementados por ciertas máquinas virtuales durante el tiempo de ejecución.
2.5.1 marco de pila
Un marco de pila consiste en un área variable local, una pila de operandos y un área de datos de marco. Cuando una máquina virtual llama a un método Java, obtiene el área de la variable local y el tamaño de la pila de operandos de este método de la información de tipo de la clase correspondiente, y asigna la memoria del marco de la pila de acuerdo con esto, y luego lo empuja a la pila Java.
2.5.1.1 Área variable local
El área variable local se organiza en una matriz contada desde 0 en unidades de longitud de palabras. La instrucción ByTecode usa los datos en él a través de un índice a partir de 0. Valores de tipos int, flotante, referencia y retornos de retornos ocupan un elemento en la matriz, mientras que los valores de los tipos byte, corto y char se convierten en valores int antes de almacenarse en la matriz, y también ocupan un elemento. Pero los valores de los tipos largos y dobles ocupan dos términos consecutivos en la matriz.
2.5.1.2 Pila de operando
Al igual que el área variable local, la pila de operando también se organiza en una matriz en la longitud de la palabra. Acceda a través de la pila de operaciones de pila estándar y se apila. Dado que no se puede acceder directamente al contador del programa mediante instrucciones del programa, las instrucciones de la máquina virtual Java obtienen operandos de la pila de operandos, por lo que su operación se basa en la pila en lugar de en los registros. La máquina virtual toma la pila de operando como su espacio de trabajo, porque la mayoría de las instrucciones tienen que aparecer datos desde aquí, realizar operaciones y luego enviar el resultado de nuevo a la pila de operando.
2.5.1.3 Área de datos de cuadro
Además del área variable local y la pila de operandos, los marcos de la pila Java también necesitan áreas de datos de cuadros para admitir el análisis constante de la piscina, el retorno del método normal y los mecanismos de despacho de excepción. Cada vez que una máquina virtual desea ejecutar una instrucción que requiera datos constantes del grupo, lo accede a través de un puntero al grupo constante en el área de datos de cuadro. Además del análisis de las piscinas constantes, el área de datos del marco también ayuda a la máquina virtual a manejar el final normal o el aborto anormal de los métodos Java. Si la devolución finaliza normalmente, la máquina virtual debe restaurar la trama de la pila del método que inicia la llamada, incluida la configuración del contador del programa para apuntar a la siguiente instrucción que inicia el método de llamada; Si el método tiene un valor de retorno, la máquina virtual debe empujarla a la pila de operando del método que inicia la llamada. Para manejar las salidas de excepción durante la ejecución del método Java, el área de datos de cuadro también contiene una referencia a la tabla de excepciones de este método.
2.6 contador de programa
Para un programa Java en ejecución, cada hilo tiene su contador de programa. Los contadores del programa también se llaman registros de PC. El contador del programa puede contener un puntero local y un retornado. Cuando un hilo ejecuta un método Java, el valor del contador del programa siempre es la dirección de la siguiente instrucción ejecutada. La dirección aquí puede ser un puntero local o un desplazamiento en el método bytecode relativo a la instrucción de inicio del método. Si el hilo está ejecutando un método local, el valor del contador del programa está "indefinido".
2.7 Pila de métodos locales
Cualquier interfaz de método local utilizará algún tipo de pila de métodos locales. Cuando un hilo llama a un método Java, la máquina virtual crea un nuevo marco de pila y lo empuja a la pila Java. Cuando llama a un método local, la máquina virtual mantiene la pila Java sin cambios y ya no empuja a la nueva pila en la pila Java roscada. La máquina virtual simplemente se conecta dinámicamente y llama directamente el método local especificado.
El área del método y el montón son compartidos por todos los hilos en la instancia de la máquina virtual. Cuando la máquina virtual carga un archivo de clase, analiza la información de tipo de los datos binarios contenidos en el archivo de clase, y luego coloca la información de tipo en el área de método. Cuando el programa se está ejecutando, la máquina virtual coloca todos los objetos creados por el programa en tiempo de ejecución en el montón.
Al igual que otras áreas de memoria de tiempo de ejecución, el área de memoria ocupada por la pila de métodos locales se puede expandir o reducir dinámicamente según sea necesario.
3 motor de ejecución
En la especificación de la máquina virtual Java, el comportamiento del motor de ejecución se define utilizando conjuntos de instrucciones. El diseñador que implementa el motor de ejecución decidirá cómo ejecutar bytecode, la implementación se puede interpretar, compilarse en la mosca o ejecutarse directamente utilizando instrucciones en el chip o una mezcla de ellos.
El motor de ejecución puede entenderse como una especificación abstracta, una implementación concreta o una instancia en ejecución. Especificaciones abstractas Use conjuntos de instrucciones para especificar el comportamiento del motor de ejecución. Una implementación específica puede usar una variedad de tecnologías diferentes, que incluyen software, hardware o una combinación de tecnología de árboles. El motor de ejecución como instancia de tiempo de ejecución es un hilo.
Cada hilo de un programa Java en ejecución es una instancia de un motor de ejecución de máquina virtual independiente. Desde el principio hasta el final del ciclo de vida del hilo, está ejecutando bytecode o ejecutando un método local.
3.1 Conjunto de instrucciones
La secuencia de código de byto del método se compone de una secuencia de instrucciones de una máquina virtual Java. Cada instrucción contiene un código de operación de un solo byte seguido de 0 o más operandos. El código de operación representa la operación que se realizará; El operando proporciona a la máquina virtual Java con información adicional necesaria para ejecutar el código de operación. Cuando una máquina virtual ejecuta una instrucción, puede usar los elementos en el grupo constante actual, los valores en la variable local de la trama actual o los valores en la parte superior de la pila de operando de la trama actual.
El motor de ejecución de resumen ejecuta una instrucción ByTecode a la vez. Cada hilo (instancia de motor de ejecución) de un programa que se ejecuta en una máquina virtual Java realiza esta operación. El motor de ejecución obtiene el código de operación, y si el código de operación tiene un operando, obtiene su operando. Realiza la acción especificada por el código de operación y el operando siguiente, y luego obtiene el siguiente código de operación. Este proceso de ejecución de ByTecode continuará hasta que se complete el hilo, y la finalización del hilo se puede marcar regresando desde su método inicial o no captura la excepción lanzada.
4 interfaz de método local
La interfaz local Java, también llamada JNI (JavanativeInterface), está preparada para la portabilidad. La interfaz del método local permite que el método local haga lo siguiente:
Pasar o devolver datos
Variables de instancia de operación
Operar variables de clase o métodos de clase de llamadas
Matriz de operando
Bloquear el objeto de montón
Cargar nueva clase
tirar una excepción
Atrapa la excepción lanzada por un método local que llama a un método Java
Capture la excepción asincrónica lanzada por la máquina virtual
Indica que un objeto de recolector de basura ya no es necesario
Resumir
Lo anterior se trata de este artículo sobre una comprensión profunda de la arquitectura de máquina virtual Java, y espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a otros temas relacionados en este sitio. Si hay alguna deficiencia, deje un mensaje para señalarlo. ¡Gracias amigos por su apoyo para este sitio!