La máquina virtual Java (JVM) es un componente central de Java Runtime Environment (JRE) que permite que los programas Java se ejecuten en cualquier plataforma sin modificaciones. JVM actúa como intérprete entre el código de bytes de Java y el hardware subyacente, proporcionando la famosa capacidad Write Once Run Anywhere (WORA) de Java.
- Fuente Java (.java) -> compilado por javac -> código de bytes (.class)
- JVM carga el código de bytes, verifica que lo vincula y luego lo ejecuta
- La ejecución puede implicar la interpretación del código de bytes o el uso de la compilación Just-In-Time (JIT) para convertir el código activo en código de máquina nativo para mejorar el rendimiento.
- La recolección de basura se ejecuta en segundo plano para recuperar memoria de objetos no utilizados
Arquitectura de JVM
La siguiente imagen muestra la arquitectura y los componentes clave de JVM.
Componentes de la arquitectura JVM
Ahora vamos a discutir cada componente de la JVM en detalle.
1. Subsistema de carga de clases
Es principalmente responsable de tres actividades.
1. Cargando
- Lee archivos .class y almacena metadatos de clases en el área de métodos.
- Crea un objeto Class en el montón que representa la clase cargada.
class GFG{ static{ System.out.println('GFG class is loaded by the JVM!'); } public void display(){ System.out.println('Method of GFG class is executed.'); } } public class Test{ public static void main(String[] args) throws Exception{ System.out.println('Main method started.'); // Loading the class explicitly using Class.forName() Class.forName('GFG'); System.out.println('Class loaded successfully.'); // Creating object to execute method GFG obj = new GFG(); obj.display(); } }
Producción
Main method started. GFG class is loaded by the JVM! Class loaded successfully. Method of GFG class is executed.
Nota: Por cada cargado .clase solo archivo uno Se crea el objeto de la clase.
2. Vinculación: Responsable de preparar la clase cargada para su ejecución. Incluye tres pasos:
- Verificación: Garantiza que el código de bytes siga las reglas de JVM y sea seguro de ejecutar.
- Preparación: Asigna memoria para variables estáticas y asigna valores predeterminados.
- Resolución: Convierte referencias simbólicas en referencias directas en la memoria.
3. Inicialización
- Asigna valores reales a variables estáticas.
- Ejecuta bloques estáticos definidos en la clase.
Tipos de cargadores de clases
- Cargador de clases Bootstrap: Carga clases principales de Java (JAVA_HOME/lib).
- Cargador de clases de extensión: Carga clases desde el directorio de extensiones (JAVA_HOME/jre/lib/ext).
- Cargador de clases de sistema/aplicación: Carga clases desde el classpath de la aplicación.
// Java code to demonstrate Class Loader subsystem public class Geeks { public static void main(String[] args) { // String class is loaded by bootstrap loader and // bootstrap loader is not Java object hence null System.out.println(String.class.getClassLoader()); // Test class is loaded by Application loader System.out.println(Geeks.class.getClassLoader()); } }
Producción
null jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f
2. Áreas de memoria JVM
- Área del método: Almacena información a nivel de clase, como el nombre de la clase, los métodos de la clase principal, las variables y los datos estáticos. Compartido en toda la JVM.
- Área del montón: Almacena todos los objetos. Compartido en toda la JVM.
- Área de pila: Cada hilo tiene su propia pila de tiempo de ejecución; El método almacena llamadas a variables locales en marcos de pila. Destruido cuando se acaba el hilo.
- Registros de PC: Mantenga la dirección de la instrucción que se está ejecutando actualmente para cada hilo.
- Pilas de métodos nativos: Cada hilo tiene una pila separada para la ejecución del método nativo.
3. Motor de ejecución
El motor de ejecución ejecuta el .class (código de bytes). Lee el código de bytes línea por línea, utiliza datos e información presentes en varias áreas de la memoria y ejecuta instrucciones. Se puede clasificar en tres partes:
- Intérprete: Interpreta el código de bytes línea por línea y luego lo ejecuta. La desventaja aquí es que cuando se llama a un método varias veces, cada vez se requiere interpretación.
- Compilador justo a tiempo (JIT): Se utiliza para aumentar la eficiencia de un intérprete. Compila todo el código de bytes y lo cambia a código nativo, de modo que cada vez que el intérprete ve llamadas repetidas a métodos, JIT proporciona código nativo directo para esa parte, por lo que no es necesaria una reinterpretación y, por lo tanto, se mejora la eficiencia.
- Recolector de basura: Destruye objetos no referenciados. Para obtener más información sobre el recolector de basura, consulte recolector de basura .
4. Interfaz nativa de Java (JNI)
Es una interfaz que interactúa con las bibliotecas de métodos nativos y proporciona las bibliotecas nativas (C C++) necesarias para la ejecución. Permite a JVM llamar a bibliotecas C/C++ y ser llamada por bibliotecas C/C++ que pueden ser específicas del hardware.
5. Bibliotecas de métodos nativos
Estas son colecciones de bibliotecas nativas necesarias para ejecutar métodos nativos. Incluyen bibliotecas escritas en lenguajes como C y C++.
comparar cadena java