La máquina virtual de Java o Java Virtual Machine, es el corazón del ecosistema de Java. Gracias a la JVM, cuando hablamos de programas Java, se puede «escribir una vez, ejecutar en cualquier parte». Al igual que otras máquinas virtuales, la JVM es también una computadora abstracta. El trabajo principal de la Java Virtual Machine es cargar los archivos de clase y ejecutar los bytecode de estas clases.
Hay varios componentes de la Java Virtual Machine, como el Class Loader o Cargador de Clases, el garbage collector (gestión automática de memoria), el intérprete, el compilador JIT, el administrador de sub procesos. En este caso, vamos a hablar sobre el Cargador de Clases.
El Class Loader o Cargador de Clases, carga archivos de clases tanto de programas como de la API de Java. Solo los archivos de clase de la API de Java que realmente necesita un programa en ejecución se cargan en la máquina virtual.
Los bytecodes se ejecutan en un motor de ejecución.
¿Que es la Carga de Clases?
La carga de clases es encontrar y cargar los tipos (clases e interfaces) en tiempo de ejecución en forma dinámica. Los datos estan contenidos en archivos binarios en formato de archivos de clase.
Fases de la carga de Clases
El sub sistema de carga de clases es responsable de algo más que ubicar e importar los datos binarios para las clases. También debe verificar la corrección de los imports, asignar e inicializar memoria para las variables de clase, y ayudar en la resolución de referencias simbólicas. Estas actividades se realizan en un orden estricto:
- Carga: buscar e importar los datos binarios para un tipo con un nombre particular y crear una clase o interface a partir de esa representación binaria.
- Enlace: realización de verificación, preparación y (opcionalmente) resolución.
- Verificación: se asegura que el tipo importado sea el correcto
- Resolución: transformando las referencias simbólicas el tipo en referencias directas.
- Inicialización: invoca el código Java que inicializa las variables de clase a sus valores iniciales apropiados.
Nota: Además de cargar las clases, un cargador de clases también es responsable de localizar los recursos. Un recurso es algunos datos (un archivo «.class», datos de configuración o una imagen, por ejemplo) que se identifican con un nombre de ruta. Los recursos normalmente se encuentran como parte de un paquete de aplicación o librería, de modo que se puedan ubicar por código en la aplicación o librería.
El mecanismo del Cargador de Clases Java
La plataforma Java utiliza un modelo de delegación para la carga de clases. La idea básica es que cada cargador de clases tiene un cargador de clases «principal». Al cargar una clase, un cargador de clase primero «delega» la búsqueda de la clase a su cargador de clase principal antes de intentar encontrar la clase en sí.
El modelo de delegación del cargador de clases es el gráfico de los cargadores de clases que pasan las solicitudes de carga entre sí. El cargador de clases bootstrap está en la raíz de este gráfico. Los cargadores de clases se crean con un solo padre de delegación y buscan una clase en los siguientes lugares:
- Cache
- Parent
- Self: el mismo
Un cargador de clases primero determina si se le ha pedido que cargue esta misma clase en el pasado. Si es así, devuelve la última clase que devolvió la última vez (es decir, la clase que se encuentra en el caché). Si no, le da al Padre o Parent la oportunidad de cargar la clase. Estos dos pasos se repiten recursivamente. Si el padre devuelve el valor nulo (o lanza una exception del tipo ClassNotFoundException), entonces el cargador de clases busca su propia ruta para la fuente de la clase.
Debido a que el cargador de clases principal siempre tiene la misma oportunidad de cargar una clase primero, el cargador de clases más cercano a la raíz carga la clase. Esto también tiene el efecto de que un cargador de clases sólo vea las clases cargadas por sí mismo o por un parent o padre, no pueden ver clases cargadas por sus hijos.
La API de Java SE históricamente tiene especificadas dos cargadores de clases:
- Cargador de clase Bootstrap: que carga las clases desde la ruta de clases bootstrap.
- Cargador de clases del sistema: que es el padre de delegación predeterminado para los nuevos cargadores de clases y, típicamente, el cargador de clases usado para cargar e iniciar la aplicación.
Cargadores de Clases en Tiempo de Ejecución ( JDK 9+)
- Cargador de clases de aplicaciones: el cargado de clases de aplicaciones se usa normalmente para definir clases en la ruta de clases de aplicaciones. Es el cargador predeterminado para módulos JDK que proporcionan herramientas o API de herramientas de exportación.
- Cargador de clases de plataforma: se selecciona (en función a la seguridad/permisos) por los módulos de Java SE y JDK.
- Bootstrap class loader: define los módulos principales de Java SE y JDK.
Los tres cargadores de clases incorporados trabajan juntos para cargar clases de la siguiente manera:
- El cargador de clases de la aplicación primero busca los módulos con nombre definidos para todos los cargadores parte de la aplicación. Su un módulo adecuado se define como un de estos cargadores, entonces ese cargador cargará la clase. Si una clase no se encuentra en un módulo con nombre definido para uno de estos cargadores, entonces el cargador de clase delega a su padre. Si su clase no encuentra una clase, entonces el cargador de clases de la aplicación busca la ruta de la clase. Las clases encontradas en la ruta de clases se cargan como miembros de módulo sin nombres de este cargador.
- El cargador de clases de la plataforma busca los módulos con nombre definidos para todos los cargadores integrados. Si un módulo adecuado se define como un de estos cargadores, entonces este cargador cargará la clase. Si no se encuentra una clase en un módulo con nombre definido para uno de estos cargadores, el cargador de clases de la plataforma delega a su padre.
- El cargador de clases bootstrap busca los módulos con nombre definido para sí mismo. Si no se encuentra una clase en un módulo con nombre definido para el cargador de rutina de carga, entonces el cargador de clase de rutina de carga busca los archivos y directorios agregados a la ruta de la clase de rutina de carga mediante la opción -Xbootclasspath /a. Las clases que se encuentran en la ruta de la clase bootstrap se cargan como miembros del módulo sin nombre.
Este artículo es parte de un conjunto de artículos que describen el funcionamiento de la Java Virtual Machine, se encuentra basado en Java Virtual Machine Internals, Part 1: Class Loader.