Arquitectura de La Máquina Virtual Java
Arquitectura de La Máquina Virtual Java
Arquitectura de La Máquina Virtual Java
Resumen
En el presente artculo se describe la Arquitectura de la Mquina Virtual Java, que es parte
medular de toda la tecnologa Java. Se hace nfasis en sus componentes principales, como el
procesador virtual Java, que se encarga de ejecutar los cdigos de operacin (bytecodes)
generados por los compiladores Java, el verificador de cdigo, que junto con el cargador de clases
y el administrador de seguridad, se encargan de implementar los mecanismos empleados para
proporcionar seguridad a los usuarios de Java. Adems, a lo largo de la discusin, se hace un
anlisis de las principales caractersticas que han hecho posible el xito de Java en nuestros das.
[English]
Artculo
1. Introduccin
Cuando una persona desarrolla una aplicacin en un lenguaje como C o C++, el archivo binario
que genera el compilador y que contiene el cdigo que implementa dicha aplicacin, se puede
ejecutar nicamente sobre la plataforma sobre la cual fue desarrollada, debido a que dicho cdigo
es especifico a esa plataforma.
La plataforma Java se encuentra por encima de otras plataformas. El cdigo que generan sus
compiladores no es especfico de una maquina fsica en particular, sino de una mquina virtual.
An cuando existen mltiples implantaciones de la Mquina Virtual Java, cada una especfica de la
plataforma sobre la cual subyace, existe una nica especificacin de la mquina virtual, que
proporciona una vista independiente del hardware y del sistema operativo sobre el que se est
trabajando. De esta manera un programador en Java "escribe su programa una vez, y lo ejecuta
donde sea"[1] .
Es precisamente la mquina virtual Java la clave de la independencia de los programas Java,
sobre el sistema operativo y el hardware en que se ejecutan, ya que es la encargada de
proporcionar la vista de un nivel de abstraccin superior, donde adems de la independencia de la
plataforma antes mencionada, presenta un lenguaje de programacin simple, orientado a objetos,
con verificacin estricta de tipos de datos, mltiples hilos, con ligado dinmico y con recoleccin
automtica de basura.
A continuacin, en la seccin 2, describiremos brevemente la historia de Java. En la seccin 3
analizaremos las ventajas y desventajas de los lenguajes que utilizan mquinas virtuales, contra
los lenguajes completamente interpretados. En la seccin 4 definiremos las propiedades que posee
el lenguaje Java y en el 5, la forma en que est estructurada para lograr estas propiedades.
Finalmente, en las secciones 6 y 7 se describen las principales desventajas de Java, contra
lenguajes totalmente compilados como C.
2. El nacimiento de Java
Java es un lenguaje de programacin de Sun Microsystems originalmente llamado "Oak", que fue
concebido bajo la direccin de James Gosling y Bill Joy, quienes pertenecan a una subsidiaria de
Sun, conocida como "FirstPerson Inc". Oak naci para programar pequeos dispositivos
electrodomsticos, como los asistentes personales digitales PADs (Personal Digital Assistants) y un
poco ms adelante se utiliz para ejecutar aplicaciones para televisores. Ninguno de estos
productos tuvo xito comercial. Gosling y Joy se quedaron con una tecnologa robusta, eficiente,
orientada a objetos, independiente de la arquitectura, pero hasta ese momento, sin ninguna utilidad
prctica.
No pas mucho tiempo, cuando en Sun se dieron cuenta de que todas estas caractersticas
cubran a la perfeccin las necesidades de las aplicaciones de Internet. De esta manera, con unos
cuantos retoques, Oak se convirti en Java.
Aunado a todas las caractersticas que posee Java (modelo de objetos dinmico, sistema estricto
de tipos, paquetes, hilos, excepciones, etctera), cuando Nestcape Inc. anunci su incorporacin
dentro de su navegador (Netscape Navigator), el nivel de inters sobre el lenguaje creci
dramticamente, debido al nmero importante de personas que utilizan WWW diariamente. Todo lo
anterior se ha conjugado para lograr el xito actual de Java, siendo el actor principal su mquina
virtual, tema de este artculo.
3. Mquina Virtual vs Lenguajes Interpretados
El concepto de mquina virtual es antiguo. Fue usado por IBM en 1959 para describir uno de los
primeros sistemas operativos que existieron en la historia de la computacin, el VM. En 1970, el
ambiente de programacin de SmallTalk llev la idea a un nuevo nivel y construy una mquina
virtual para soportar abstracciones orientadas a objetos de alto nivel, sobre las mquinas
subyacentes.
Como ya hemos esbozado, las mquinas virtuales tienen varias ventajas importantes. La primera
es que presentan un medio excelente para alcanzar la portabilidad. Otra de las ventajas
importantes, es que introduce otro nivel de abstraccin y de proteccin, entre la computadora y el
software que ejecuta sobre ella. Esto cobra particular importancia en un ambiente donde el cdigo
que ejecutamos proviene de algn lugar del mundo y es escrito por alguna "buena" persona.
3.1. Lenguajes Totalmente Interpretados
Es posible decir que los lenguajes totalmente interpretados, como Tcl y JavaScript, tambin poseen
las cualidades de ser altamente portables y seguros, pero existe una diferencia importante entre
este tipo de lenguajes y los basados en una mquina virtual: la eficiencia.
Para ejecutar un programa escrito en un lenguaje completamente interpretado, el intrprete debe
realizar el anlisis lxico y sintctico en el momento de estar ejecutando el programa, lo que
provoca una sobrecarga muy considerable en la ejecucin del mismo. De hecho, en algunas
pruebas informales Tcl puede ser hasta 200 veces ms lento que C [1].
3.2. Lenguajes Compilados de Cdigo Intermedio
Los lenguajes basados en una mquina virtual, comnmente son ms rpidos que los totalmente
interpretados, debido a que utilizan una arquitectura de cdigo intermedio. La idea es dividir la
tarea de ejecutar un programa en dos partes. En la primera, se realiza el anlisis lxico y sintctico
del programa fuente, para generar el programa en instrucciones del procesador virtual (cdigo
intermedio) y en el segundo paso, se itera sobre el cdigo intermedio para obtener la ejecucin
final del programa.
Los lenguajes compilados de cdigo intermedio, pueden llegar a ser un orden de magnitud ms
rpido que los lenguajes completamente interpretados, pero, por consiguiente, un orden de
magnitud ms lentos que lenguajes optimizados como C o C++ [1].
4. Propiedades del Lenguaje Java
Se dice que el cdigo Java esportable , debido a que es posible ejecutar el mismo archivo de
clase (.class), sobre una amplia variedad de arquitecturas de hardware y de software, sin ninguna
modificacin.
Java es un lenguaje dinmico, debido a que las clases son cargadas en el momento en que son
necesitadas (dinmicamente), ya sea del sistema de archivos local o desde algn sitio de la red
mediante algn protocolo URL.
Java tiene la capacidad de aumentar su sistema de tipos de datos dinmicamente o en tiempo de
ejecucin. Este "enlace tardo" (late-binding) significa que los programas slo crecen al tamao
estrictamente necesario, aumentando as la eficiencia del uso de los recursos. Java hace menos
suposiciones sobre las implantaciones de las estructuras de datos, que los lenguajes estticos de
"enlace temprano" o en tiempo de compilacin (early-binding) como C o C++.
Debido a que Java naci en la era post-Internet, fue diseado con la idea de la seguridad y la
fiabilidad, por lo que se le integraron varias capas de seguridad para evitar [2] que programas
maliciosos pudiesen causar daos en los sistemas, sobre los que ejecuta la implantacin de la
Mquina Virtual Java.
5. La Mquina Virtual Java (MVJ)
La Mquina Virtual Java es el ncleo del lenguaje de programacin Java. De hecho, es imposible
ejecutar un programa Java sin ejecutar alguna implantacin de la MVJ. En la MVJ se encuentra el
motor que en realidad ejecuta el programa Java y es la clave de muchas de las caractersticas
principales de Java, como la portabilidad, la eficiencia y la seguridad.
Siempre que se corre un programa Java, las instrucciones que lo componen no son ejecutadas
directamente por el hardware sobre el que subyace, sino que son pasadas a un elemento de
software intermedio, que es el encargado de que las instrucciones sean ejecutadas por el
hardware. Es decir, el cdigo Java no se ejecuta directamente sobre un procesador fsico, sino
sobre un procesador virtual Java, precisamente el software intermedio del que habamos hablado
anteriormente.
La representacin de los cdigos de instruccin Java (bytecode) es simblica, en el sentido de que
los desplazamientos e ndices dentro de los mtodos no son constantes, sino que son cadenas de
caracteres o nombres simblicos. Estos nombres son resueltos la primera vez que se ejecuta el
mtodo, es decir, el nombre simblico se busca dentro del archivo de clase (.class) y se determina
el valor numrico del desplazamiento. Este valor es guardado para aumentar la velocidad de
futuros accesos. Gracias a esto, es posible introducir un nuevo mtodo o sobreescribir uno
existente en tiempo de ejecucin, sin afectar o romper la estructura del cdigo.
En la figura 1 puede observarse la capa de software que implementa a la mquina virtual Java.
Esta capa de software oculta los detalles inherentes a la plataforma, a las aplicaciones Java que se
ejecuten sobre ella. Debido a que la plataforma Java fue diseada pensando en que se
implementara sobre una amplia gama de sistemas operativos y de procesadores, se incluyeron
Cargador de clases. Su funcin es cargar dinmicamente las clases Java a partir de los
archivos de clase (.class).
Es la entidad de hardware o software, que ejecuta las instrucciones contenidas en los cdigos de
operacin (bytecodes) que implementan los mtodos Java. En las versiones iniciales de Sun, el
motor de ejecucin consista de un interprete de cdigos de operacin. En las versiones ms
avanzadas de nuestros das, se utiliza la tecnologa de "generacin de cdigo justo en el momento"
(Just-in-Time code generation), en dnde las instrucciones que implementan a los mtodos, se
convierten en cdigo nativo que se ejecuta directamente en la mquina sobre la que se subyace. El
cdigo nativo se genera nicamente la primera vez que se ejecuta el cdigo de operacin Java, por
lo que se logra un aumento considerable en el rendimiento de los programas.
5.3. El Conjunto de Instrucciones del Procesador Virtual
Muchas de las instrucciones del procesador virtual Java, son muy similares a las que se pueden
encontrar para los procesadores comunes y corrientes, como los Intel, es decir, incluyen los grupos
de instrucciones tpicos como los aritmticos, los de control de flujo, de acceso a memoria, a la pila,
etctera.
Una de las caractersticas ms significativas del conjunto de instrucciones del procesador virtual
Java, es que estn basadas en la pila y utilizan "posiciones de memoria" numeradas, en lugar de
registros. Esto es hasta cierto punto lgico, debido a que la mquina virtual est pensada para
correr sobre sistemas con procesadores sustancialmente diferentes. Es difcil hacer suposiciones
sobre el nmero o tipo de registros que estos pudiesen tener. Esta caracterstica de estar basada
en operaciones sobre la pila, impone una desventaja a los programas escritos en Java, contra los
lenguajes completamente compilados, como C o C++, debido a que los compiladores de estos
pueden generar cdigo optimizado para la plataforma particular sobre la que se est trabajando,
haciendo uso de los registros, etctera.
Varias de las instrucciones que componen el conjunto de instrucciones del procesador virtual de
Java, son bastante ms complejas que las que se pueden encontrar en procesadores comunes.
Ejemplo de ello, tenemos las casi 20 instrucciones para realizar operaciones, tales como invocar
mtodos de objetos, obtener y establecer sus propiedades o generar y referenciar nuevos objetos.
Es evidente que operaciones de este estilo son de una complejidad considerable y la proyeccin a
sus respectivas instrucciones, sobre el conjunto de instrucciones del procesador de la mquina,
implicar a varias decenas de esas instrucciones.
5.4. El Verificador de Java
Como hemos mencionado anteriormente, una de las principales razones para utilizar una mquina
virtual, es agregar elementos de seguridad a nuestro sistema, por lo que si un intrprete falla o se
comporta de manera aleatoria, debido a cdigo mal formado, es un problema muy serio. La
solucin trivial a este problema sera incluir cdigo encargado de capturar errores y verificar que el
cdigo sea correcto. Es evidente que la principal desventaja de esta solucin, es que volveremos a
caer en un sistema sumamente seguro, pero altamente ineficiente.
Los diseadores de Java tomaron otro camino. Cuando estaban diseando el conjunto de
instrucciones para la mquina virtual de Java, tenan dos metas en mente. La primera era que el
conjunto de instrucciones fuera similar a las instrucciones que se pueden encontrar en los
procesadores reales. La segunda era construir un conjunto de instrucciones que fuera fcilmente
verificable.
En Java, justo despus de que se obtiene una clase del sistema de archivos o de Internet, la
mquina virtual puede ejecutar un verificador que se encargue precisamente de constatar que la
estructura del archivo de clase es correcta. El verificador se asegura que el archivo tenga el
nmero mgico (0xCAFEBABE) y que todos los registros que contiene el archivo tengan la longitud
correcta, pero an ms importante, comprueba que todos los cdigos de operacin sean seguros
de ejecutar. Es importante notar que Java no necesita que el verificador se ejecute sobre el archivo
de clase, sino que es activado por el sistema en tiempo de ejecucin y slo sobre clases que el
mismo sistema decida. Por lo comn, las clases verificadas son las provenientes de Internet.
An en nuestros das, los cargadores de clases comerciales tienen varios defectos, por lo que la
construccin de mejores verificadores sigue siendo un problema abierto. Por ejemplo, Karsten
Sohr, en septiembre de 1999 encontr que el cargador de Microsoft tiene problemas con los tipos
de datos, entre los bloques de excepciones, lo que puede provocar forzamientos de conversiones
de tipos arbitrarios, comprometiendo la seguridad del sistema, debido a que de esta manera es
posible acceder a recursos que debieran estar restringidos.
5.5. Administrador de Memoria
Java utiliza un modelo de memoria conocido como "administracin automtica del
almacenamiento" (automatic storage management), en el que el sistema en tiempo de ejecucin de
Java mantiene un seguimiento de los objetos. En el momento que no estn siendo referenciados
por alguien, automticamente se libera la memoria asociada con ellos. Existen muchas maneras de
implementar recolectores de basura, entre ellas tenemos:
Existen muchos otros algoritmos para implementar sistemas que cuenten con recoleccin de
basura. En [6] se puede encontrar una panormica bastante completa del estado del arte actual a
ese respecto.
5.6. Administrador de Errores y Excepciones
Las excepciones son la manera como Java indica que ha ocurrido algo "extrao" [4]durante la
ejecucin de un programa Java. Comnmente las excepciones son generadas y lanzadas por el
sistema, cuando uno de estos eventos ocurre. De la misma manera, los mtodos tienen la
capacidad de lanzar excepciones, utilizando la instruccin de la MVJ, athrow.
Todas las excepciones en Java son instancias de la clase java.lang.Throwable o de alguna otra que
la especialice. Las clases java.lang.Exception y java.lang.Error, heredan directamente de
java.lang.Throwable. La primera se utiliza para mostrar eventos, de los cuales es posible
recuperarse, como la lectura del fin de archivo o la falla de la red, mientras que la segunda se
utiliza para indicar situaciones de las cuales no es posible recuperarse, como un acceso indebido a
la memoria.
llamadas a los mtodos pertenecientes a la clase java.lang.Thread. En [8] puede encontrarse una
descripcin ms detallada sobre la interfaz de hilos de Java, as como un anlisis de sus
caractersticas ms importantes.
5.9. Cargador de Clases
Los programas Java estn completamente estructurados en clases. Por lo tanto, una funcin muy
importante del sistema en tiempo de ejecucin, es cargar, enlazar e inicializar clases
dinmicamente, de forma que sea posible instalar componentes de software en tiempo de
ejecucin. El proceso de cargado de las clases se realiza sobre demanda, hasta el ltimo momento
posible.
La Mquina Virtual Java utiliza dos mecanismos para cargar las clases. El primero consiste en un
cargador de clases del sistema, cuya funcin es cargar todas las clases estndar de Java, as
como la clase cuyo nombre es estrada va la lnea de comandos. De manera adicional, existe un
segundo mecanismo para cargar clases dentro del sistema, utilizando una instancia de la
clasejava.lang.ClassLoader o alguna otra definida por el usuario, que especialice a la anterior. Es
importante hacer notar que el cargador de clases es uno de los recursos que debe proteger el
administrador de seguridad. No debe permitir, por ejemplo, que los applets no confiables creen sus
propios cargadores debido a que puede ser un punto por el que pueden romperse las restricciones
de seguridad.
Los cargadores especializados por los programadores, pueden definir la localizacin remota de
donde se cargarn las clases o asignar atributos de seguridad apropiados para sus aplicaciones
particulares. Finalmente, se puede usar a los cargadores para proporcionar espacios de nombres
separados a diferentes componentes de una aplicacin.
5.10. Arquitectura de Seguridad en Java
Java utiliza una serie de mecanismos de seguridad, con el fin de dificultar la escritura de
programas maliciosos que pudiesen afectar la integridad de las aplicaciones y los datos de los
usuarios. Cada sistema en tiempo de ejecucin Java tiene la capacidad de definir sus propias
polticas de seguridad, mediante la implantacin de un "administrador de seguridad" (security
manager), cuya funcin es proteger al sistema de tiempo de ejecucin, definiendo el mbito de
cada programa Java en cuanto a las capacidades de acceder a ciertos recursos, etctera.
El modelo de seguridad original proporcionado por la plataforma Java, es conocido como la "caja
de arena" [4] (sandbox), que consiste en proporcionar un ambiente de ejecucin muy restrictivo
para cdigo no confiable que haya sido obtenido de la red. Como se muestra en la figura 3 , la
esencia del modelo de la caja de arena, es que el cdigo obtenido del sistema de archivo local es
por naturaleza confiable. Se le permite el acceso a los recursos del sistema, como el mismo
sistema de archivos o los puertos de comunicacin. Mientras, el cdigo obtenido de la red se
considera no confiable. Por lo tanto, tiene acceso nicamente a los recursos que se encuentran
accesibles desde la caja de arena.
Como hemos mencionado, la mquina implementa otros mecanismos de seguridad, desde el nivel
de lenguaje de programacin, como la verificacin estricta de tipos de datos, manejo automtico de
la memoria, recoleccin automtica de basura, verificacin de los lmites de las cadenas y arreglos,
etctera. Todo con el fin de obtener, de una manera relativamente fcil, cdigo "seguro".
En segunda instancia, los compiladores y los verificadores de cdigo intentan asegurar que slo se
ejecuten cdigos de ejecucin (bytecodes) Java, con la estructura correcta y no maliciosos.
Asimismo, analizamos cmo con el cargador de clases se pueden definir espacios de nombres
locales, lo que ayuda a garantizar que un applet no confiable pueda interferir con el funcionamiento
de otros programas.
Finalmente, el acceso a los recursos importantes del sistema, es administrado entre el sistema de
tiempo de ejecucin y el administrador de seguridad (Security Manager), que es implementado por
la clase java.lang.SecurityManager, que permite a las implantaciones incorporar polticas de
seguridad. De esta manera, es posible para las aplicaciones determinar si una operacin es
insegura o contraviene las polticas de seguridad, antes de ejecutarla.
Ver figura 4
El JDK 1.1 introduce el concepto de "applet firmado" (signed applet), en el que los applets que
poseen una firma digital correcta, son considerados como confiables. Por lo tanto, reciben los
mismos privilegios que el cdigo obtenido del sistema de archivos. Los applets firmados, junto con
la firma, se envan en un archivo de formato JAR (Java Archive). En este modelo de applets sin
firma, continan corriendo en la caja de arena. En la figura se puede observar el modelo de
seguridad del JDK 1.1.
Finalmente, como se muestra en la figura 5, en la arquitectura de la plataforma de seguridad de
Java 2 se introdujeron diferentes niveles de restriccin, se elimin la idea de que el cdigo
proveniente del sistema de archivo local siempre es confiable, etctera. Para mayor informacin
sobre los mecanismos de seguridad de Java consultar [3].
6. Desventajas de las Mquinas Virtuales
Una de las razones por que las mquinas virtuales no son la panacea de la computacin, es que
agregan gran complejidad al sistema en tiempo de ejecucin. Por ejemplo, la MVJ espera que la
computadora sobre la que subyace, soporte el estndar de IEEE para los nmeros de punto
flotante de 32 y 64 bits, as como enteros largos de 64 bits. La mayora de las plataformas lo hacen
pero hay algunas que no, lo que implica trabajo extra.
La principal desventaja de los lenguajes basados en mquina virtual, es que efectivamente son
ms lentos que los lenguajes completamente compilados, debido a la sobrecarga que genera tener
una capa de software intermedia entre la aplicacin y el hardware de la computadora. Esta
desventaja no es demasiado crtica. Cabe recordar que no hace mucho tiempo sucedi una historia
similar entre C y los lenguajes ensambladores. La mayora de los programadores de ese tiempo
(programadores de ensamblador), se resistan al cambio, argumentando que el uso de un lenguaje
como C impondra demasiada sobrecarga a sus aplicaciones. Es por esto que no sera raro que, en
un futuro prximo, la historia se repita.
6.1 Deficiencias de la MVJ
Difcil de extender. Debido a que se utiliza un byte para codificar el cdigo de operacin de
las instrucciones del procesador virtual Java (de ah el nombre de bytecode), es difcil
agregar nuevas instrucciones.
[1]
[2]
As como los procesadores fsicos tienen asociado un lenguaje ensamblador, el procesador virtual
Java posee el propio. Ejemplo es Jasmin, que puede encontrarse en
http://cat.nyu.edu/meyer/jasmin/resources.html.
[4]
Las excepciones pueden indicar eventos de muy diversa ndole, desde errores por accesos
indebidos a la memoria, fallos en la red o alcanzar el fin de archivo en una lectura. .
Bibliografa
[1] Jon Meyer . Troy Downing . (1997) Java Virtual Machine. O'Reilly.
[2] Douglas Kramer. (1996) The Java Platform. JavaSoft .
[3] Lindholm, Tim . Lindholm Yellin. Frank . The JavaTM Virtual Machine Specification. Sun
Microsystems, Inc.. Second Edition http://www.javasoft.com/docs/books/vmspec.
[4] http://java.sun.com/products/jdk/1.3/docs/guide/security.