La JVM(Java Virtual Machine) actúa como un motor de tiempo de ejecución para ejecutar aplicaciones Java. La JVM es la que realmente llama al método principal presente en un código java. JVM es una parte de JRE (Java Runtime Environment).
Las aplicaciones Java se llaman WORA (Write Once Run Anywhere). Esto significa que un programador puede desarrollar código Java en un sistema y puede esperar que se ejecute en cualquier otro sistema habilitado para Java sin ningún ajuste. Todo esto es posible gracias a JVM.
Cuando compilamos un archivo .java, el compilador de Java genera archivos .class (que contienen código de bytes) con los mismos nombres de clase presentes en el archivo .java. Este archivo .class entra en varios pasos cuando lo ejecutamos. Estos pasos juntos describen toda la JVM.
Subsistema del cargador de clases
Se encarga principalmente de tres actividades.
- Carga
- Enlace
- Inicialización
- El nombre completamente calificado de la clase cargada y su clase padre inmediata.
- Si el archivo «.class» está relacionado con Class o Interface o Enum.
- Información de modificadores, variables y métodos, etc.
- Verificación: Asegura la corrección del fichero .class es decir, comprueba si este fichero está correctamente formateado y generado por un compilador válido o no. Si la verificación falla, obtenemos la excepción en tiempo de ejecución java.lang.VerifyError. Esta actividad la realiza el componente ByteCodeVerifier. Una vez que esta actividad se completa entonces el archivo de clase está listo para la compilación.
- Preparación: La JVM asigna memoria para las variables de la clase e inicializa la memoria con los valores por defecto.
- Resolución: Es el proceso de sustituir las referencias simbólicas de la clase por referencias directas. Se realiza buscando en el área del método para localizar la entidad referenciada.
- Cargador de clases de arranque: Toda implementación de JVM debe tener un cargador de clases bootstrap, capaz de cargar clases de confianza. Carga las clases del núcleo de la API de java presentes en el directorio «JAVA_HOME/jre/lib». Esta ruta se conoce popularmente como la ruta de arranque. Se implementa en lenguajes nativos como C, C++.
- Cargador de clases de extensión: Es un hijo del cargador de clases bootstrap. Carga las clases presentes en los directorios de extensiones «JAVA_HOME/jre/lib/ext»(Extension path) o cualquier otro directorio especificado por la propiedad del sistema java.ext.dirs. Se implementa en java mediante la clase sun.misc.Launcher$ExtClassLoader.
- Cargador de clases del sistema/aplicación: Es un hijo del cargador de clases de extensión. Es responsable de cargar las clases desde el classpath de la aplicación. Internamente utiliza la variable de entorno que se asigna a java.class.path. También está implementado en Java por la clase sun.misc.Launcher$AppClassLoader.
- Área de métodos: En el área de métodos se almacena toda la información a nivel de clase como el nombre de la clase, el nombre de la clase padre inmediata, la información de los métodos y las variables, etc., incluyendo las variables estáticas. Sólo hay un área de métodos por JVM, y es un recurso compartido.
- Área de Heap: La información de todos los objetos se almacena en el área de heap. También hay un área de Heap por JVM. También es un recurso compartido.
- Área de pila: Para cada hilo, la JVM crea una pila de tiempo de ejecución que se almacena aquí. Cada bloque de esta pila se llama registro de activación/marco de pila que almacena las llamadas a métodos. Todas las variables locales de ese método se almacenan en su marco correspondiente. Después de que un hilo termine, su pila de tiempo de ejecución será destruida por JVM. No es un recurso compartido.
- Registros PC: Almacenan la dirección de la instrucción de ejecución actual de un hilo. Obviamente, cada hilo tiene registros PC separados.
- Pilas de métodos nativos: Para cada hilo se crea una pila nativa independiente. En ella se almacena la información de los métodos nativos.
- Intérprete: Interpreta el bytecode línea por línea y luego lo ejecuta. La desventaja aquí es que cuando un método se llama varias veces, cada vez se requiere la interpretación.
- Compilador Justo en 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 a métodos repetidas, el JIT proporciona código nativo directo para esa parte, de modo que no se requiere reinterpretación, por lo que se mejora la eficiencia.
- Recolector de basura: Destruye los objetos no referenciados. Para más información sobre el Garbage Collector, consulte Garbage Collector.
Carga: El cargador de clases lee el archivo «.class», genera los datos binarios correspondientes y los guarda en el área de métodos. Para cada archivo «.class», JVM almacena la siguiente información en el área de métodos.
Después de cargar el archivo «.class», JVM crea un objeto de tipo Class para representar este archivo en la memoria del heap. Tenga en cuenta que este objeto es de tipo Class predefinido en el paquete java.lang. Este objeto Class puede ser utilizado por el programador para obtener información a nivel de clase como el nombre de la clase, el nombre del padre, los métodos y la información de las variables, etc. Para obtener esta referencia de objeto podemos utilizar el método getClass() de la clase Object.
import
java.lang.reflect.Field;
import
java.lang.reflect.Method;
public
class
Test {
public
static
void
main(String args)
{
Student s1 =
new
Student();
Class c1 = s1.getClass();
System.out.println(c1.getName());
Method m = c1.getDeclaredMethods();
for
(Method method : m)
System.out.println(method.getName());
Field f = c1.getDeclaredFields();
for
(Field field : f)
System.out.println(field.getName());
}
}
class
Student {
private
String name;
private
int
roll_No;
public
String getName() {
return
name; }
public
void
setName(String name) {
this
.name = name; }
public
int
getRoll_no() {
return
roll_No; }
public
void
setRoll_no(
int
roll_no)
{
this
.roll_No = roll_no;
}
}
StudentgetNamesetNamegetRoll_nosetRoll_nonameroll_No
Student s2 = new Student();// c2 will point to same object where // c1 is pointingClass c2 = s2.getClass();System.out.println(c1==c2); // true
Enlace: Realiza la verificación, preparación y (opcionalmente) la resolución.
Inicialización: En esta fase se asignan todas las variables estáticas con sus valores definidos en el código y el bloque estático(si lo hay). Esto se ejecuta de arriba a abajo en una clase y de padre a hijo en la jerarquía de clases.
En general, hay tres cargadores de clases :
public
class
Test {
public
static
void
main(String args)
{
System.out.println(String.
class
.getClassLoader());
System.out.println(Test.
class
.getClassLoader());
}
}
nulljdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f
Nota: JVM sigue el principio de Delegación-Herarquía para cargar clases. El cargador de clases del sistema delega la solicitud de carga al cargador de clases de extensión y el cargador de clases de extensión delega la solicitud al cargador de clases de arranque. Si se encuentra una clase en la ruta del boot-strap, la clase se carga, de lo contrario la solicitud se transfiere de nuevo al cargador de clases de extensión y luego al cargador de clases del sistema. Por último, si el cargador de clases del sistema no puede cargar la clase, entonces obtenemos la excepción en tiempo de ejecución java.lang.ClassNotFoundException.
Memoria JVM
Motor de ejecución
El motor de ejecución ejecuta el «.class» (bytecode). Lee el código de bytes línea por línea, utiliza los datos y la información presente en varias zonas de memoria y ejecuta las instrucciones. Se puede clasificar en tres partes:
Java Native Interface (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 la JVM llamar a librerías C/C++ y ser llamada por librerías C/C++ que pueden ser específicas del hardware.
Librerías de Métodos Nativos :
Es una colección de las Bibliotecas Nativas(C, C++) que son requeridas por el Motor de Ejecución.
Este artículo ha sido contribuido por Gaurav Miglani. Si te gusta GeeksforGeeks y te gustaría contribuir, también puedes escribir un artículo usando contribute.geeksforgeeks.org o enviando tu artículo por correo a [email protected]. Verás cómo tu artículo aparece en la página principal de GeeksforGeeks y ayudarás a otros Geeks.
Por favor, escribe comentarios si encuentras algo incorrecto, o quieres compartir más información sobre el tema tratado anteriormente.