Funcionamiento de la JVM

 

Interpretación

JVM

JRE

Memoria

Interfaz de bajo nivel


 

Interpretación

El método tradicional de implementación de Java es por medio de un intérprete que corresponde a la máquina virtual de Java. Un compilador permite traducir el código fuente en archivos "class" que contienen instrucciones en bytecode (independientes de la máquina). Estos archivos "class" son rcuperados e interpretados por la máquina virtual. Los servicios comunes son ofrecidos en forma de bibliotecas de clases o "so" archivos de bibliotecas compartidos. Las bibliotecas de clases proveen servicios a la JVM y a los programas en byecode, en particular el coporte de lenguaje básico y las funcionalidades extendidas. Una biblioteca de tiempo de ejecución provee el elemento de bajo nivel llamado "Recolección de Desperdicios", el soporte de "hilos" y ejecuta directamente en el hardware de la máquina.

 


 

La Máquina virtual de Java

La Máquina virtual de Java es una máquina de pila. Las instrucciones interpretadas por la máquina virtual manipulan datos almacenados en lo que se llama "slots" de pila.

 

El contenido ejecutable de un archivo de bytecodes contiene un vector de instrucciones bytecode para cada método. Los bytecode son instrucciones para la máquina virtual,las cuales tienen algunos registros de variables locales y una pila usada para evaluación de expresiones. Las primeras variables locales son inicializadas con los parámetros actuales. Cada variable local o "slot de la pila es una palabra que corresponde a un entero de 32 bits, a un punto flotante o a una referencia a objeto (puntero). Para puntos flotantes dobles y enteros largos se utilizan dos slots.

 

Los slots no están relacionados a un tipo, es decir, en algún punto un slot podría contener un valor entero y en otro, el mismo slot podría contener una referencia a objeto. Sin embargo, no se puede almacenar un entero en un slot y luego recuperar esos bts reinterpretándolos como una referencia a objeto. Aún más, en cualquier punto del programa, cada slot tiene un único tipo que puede ser determinado usando un flujo estático de datos. El tipo podría ser "no asignado", con lo cual no se permite leer el valor del slot. Estas restricciones son parte del modelo de seguridad de Java y se ven reforzadas por el verificador de bytecodes.

 

El intérprete lee el flujo de bytecodes y realiza la operación especificada. Lo más simple de la máquina virtual es conocer el intérprete de bytecode. El código interpretado es, generalmente, más lento que un programa escrito en un lenguaje compilado, y Java no es distinto en este aspecto.

 

Han habido muchas características en la aproximación para definir el rendimiento de los intérpretes. Una muy común hoy en día es incluir un compilador relativamente simple en el tiempo de ejecución de la máquina virtual. Mejor que interpretar los programas en bytecodes, las clases y sus métodos son compilados en el momento al interior de la máquina virtual y la representación compilada es ejecutada cuando se hace la llamada al método. Esto es conocido como un compilador en el instante o JIT (Just In Time).

 

El proceso de compilación genera varios problemas:

 

Nos gustaría manejar constantes, lo que es posible en algún nivel del árbol que representa la sintaxis. Sin embargo, los nodos de ese árbol no manejan tipos.

Una aproximación sin mayores complicaciones usaría montones de registros virtuales y el código generado sería muy malo. Ejecutando el optimizador, el código generado podría corregirse, pero se mantendría la pila de registros sin usar. Sería agradable no tener que ejecutar el optimizador y no agregar trabajo extra a esto.

La representación del RTL (Lenguaje de traducción de registros) es semi-tipeada, dado que distingue los variados modos, tales como punteros, distintos tamaños de enteros y punto flotantes. Esto causa problemas, ya que un slot de pila de Java puede tener distintos tipos en distintos puntos del código.

 

El último problema se resuelve usando un registro virtual separado por cada modo de máquina. Un slot de pila en lugar de ser mapeado a un único registro virtual es mapeado a una familia de registros virtuales, uno por cada modo de máquina.

 


  

El ambiente de ejecución

Para ejecutar un determinado programa, se requiere un entorno ejecutable definido. Esto es, en principio, similar a C++, que requiere una biblioteca de ejecución, así como soporte para solicitud de memoria, excepciones, etc. Sin embargo, Java requiere más soporte de ejecución que los lenguajes "tradicionales". También requiere soporte para

Recolección de desperdicios, hilos, reflexión de tipos y todos los métodos primitivos de Java.

 


 

Memoria

El efecto de maximizar la velocidad de ejecución y minimizar el consumo de memoria es uno de los puntos de mayor atención, sobre todo en los sistemas insertos. En el modelo estándar de Java, junto con el espacio necesario para el código del usuario existe también un cuerpo sustancial de código fijo para la JVM y el entorno de ejecución. Este código incluye, por ejemplo, bibliotecas estándar, código para carga de nuevas clases, un recolector de desperdiciosy un posible intérprete de máquina virtual.

 

Algunas aplicaiones pueden necesitar acceder a clases dinámicamente cargadas y a grandes bibliotecas de clases. Otras aplicaciones pueden no necesitar nada de esto y no verse afectadas por los requerimientos de espacio de estas características. En un ambiente de escasa memoria, sería deseable dejar fuera algo de este código de apoyo. Por ejemplo, si no hay necesidad de cargar nuevas clases en tiempo d ejecución, el código para leer archivos de clases e interpretar bytecodes, podría omitirse.

 

Dadas estas diferencias, los espacios mínimos de memoria de ejecución y de código serían:

Aplicación Mínima: 32k ROM, 8k RAM.

Aplicación Mínima con código dinámico: 128k ROM, 32k RAM.

 


 

Interfaces de Bajo Nivel

El ambiente de ejecución provee un conjunto de servicios a la aplicación que lo utiliza. Muchos de estos servicios es posible proveerles internamente. Para proveer otros servicios, es necesario para el entorno de ejecución o bien comunicarse con otro subsistema o acceder al hardware subyacente. Para facilitar esto, un conjunto de interfaces internas de bajo-nivel deben ser definidas entre el entorno de ejecución y el ambiente de hardware y software en el que residen.

 

Podría ser posible codificar directamente al hardware. Sin embargo, definir un conjunto limpio de abstracciones hechas para facilitar el apoyo de objetivos adicionales y el desarrollo de código para dispositivos reales y sistemas con sus distintas características de hardware, antes que sólo desarrollar aplicaciones para ejecución en bancos de prueba. Podrían definirse las siguientes interfaces de bajo nivel:

 

interfaz a la plataforma de colocación de memoria

interfaz a la fuente de interrupciones periódicas (opcional)

interfaz a las facilidades para fecha y hora

interfaz a las primitivas del ambiente destino de "hilos" (opcional)

interfaz del iniciador del entorno de ejecución

interfaz de depuración