java - ventajas - ¿Qué es una máquina virtual y por qué los lenguajes dinámicos la necesitan?
que es jvm en programacion (8)
Desde la entrada de wikipedia en Máquinas Virtuales :
"Una máquina virtual (VM) es una implementación de software de una máquina (es decir, una computadora) que ejecuta programas como una máquina física".
El mayor activo de las máquinas virtuales es, en teoría, la portabilidad de código: "escribir una vez, ejecutar en cualquier lugar"
Probablemente el ejemplo más conocido de una máquina virtual es la JVM , originalmente diseñada para ejecutar código Java, pero ahora también se usa cada vez más para idiomas como Clojure y Scala.
No hay nada específico para los lenguajes dinámicos que significa que necesitan una VM. Sin embargo, sí necesitan un interpreter , que podría construirse en una máquina virtual.
Entonces, por ejemplo, Python y Java tienen una VM, C y Haskell no. (Corrígeme si me equivoco)
Pensando en qué idiomas tienen los dos lados de la línea, no puedo encontrar la razón. Java es estático en muchos sentidos, mientras que Haskell proporciona muchas características dinámicas.
Imagine que creó un lenguaje de programación: descubrió la semántica del lenguaje y desarrolló una buena sintaxis.
Sin embargo, una representación textual no es suficiente: tener que analizar el texto una y otra vez al ejecutar un programa es ineficiente, por lo que es natural agregar una representación binaria en memoria. Combine eso con un administrador de memoria personalizado, y básicamente tiene una máquina virtual.
Ahora, para obtener puntos adicionales, desarrolle un formato de código de bytes para la serialización de su representación en memoria y un cargador de tiempo de ejecución, o, si desea seguir los lenguajes de scripting, una función eval()
.
Para la gran final, agregue un JIT.
Java y Python se pueden compilar de una manera que mantenga la independencia de la plataforma. Esto se mantiene incluso para C #. Las ventajas son que las máquinas virtuales son capaces de convertir este código de bytes en su mayoría fuertemente tipado en muy buen código específico de plataforma con relativamente poca sobrecarga. Dado que Java está pensado para "compilarse una vez, ejecutarlo en cualquier lugar", se ha creado la JVM.
No hay "necesidad", cualquiera de estos lenguajes proporciona compiladores que emiten directamente el código de la máquina para implementar la semántica de su lenguaje en una arquitectura determinada.
La idea de una máquina virtual es abstraer las diferencias arquitectónicas entre los diferentes fabricantes de hardware y software para que los desarrolladores tengan una sola máquina para escribir.
No tiene nada que ver con estática o dinámica.
Más bien, se trata de independizarse de la plataforma de hardware subyacente ("compilar una vez, ejecutar en todas partes", en teoría ...)
En realidad, tampoco tiene nada que ver con el lenguaje. Uno podría escribir un compilador de C que genere un código de bytes para la JVM. Uno podría escribir un compilador de Java que genere el código de máquina x86.
Olvidémonos de las máquinas virtuales por un segundo (volveremos a las siguientes, lo prometo), y comencemos con este hecho importante:
C no tiene recolección de basura.
Para que un lenguaje proporcione recolección de basura, tiene que haber algún tipo de "runtime" / runtime-environment / thing que lo realizará.
Es por eso que Python, Java y Haskell requieren un "tiempo de ejecución" , y C, que no lo hace, puede simplemente compilar directamente en código nativo.
Tenga en cuenta que psyco era un optimizador de Python que compilaba código de Python en código de máquina; sin embargo, gran parte de ese código de máquina consistía en llamadas a las funciones de tiempo de ejecución de C-Python, como PyImport_AddModule
, PyImport_GetModuleDict
, etc.
Haskell / GHC se encuentra en un barco similar a Python compilado de forma psicoactiva. Int
s se agregan como instrucciones simples de la máquina, pero las cosas más complicadas que asignan objetos, etc., invocan el tiempo de ejecución.
¿Qué más?
C no tiene "excepciones"
Si tuviéramos que agregar excepciones a C, nuestro código de máquina generado tendría que hacer algunas cosas para cada función y para cada llamada de función.
Si luego agregamos "cierres" también, se agregarían más cosas.
Ahora, en lugar de tener este código de máquina repetitivo repetido en cada función, podríamos hacerlo en lugar de llamar a un subprocedimiento para hacer las cosas necesarias, algo como PyErr_Occurred
.
Así que ahora, básicamente, cada línea de origen original se asigna a algunas llamadas a algunas funciones y una parte única más pequeña.
Pero mientras hagamos tantas cosas por línea de código fuente original, ¿por qué molestarse con el código de máquina?
Aquí hay una idea (por cierto, llamémosla "Máquina Virtual").
Vamos a representar su código Python, que es por ejemplo:
def has_no_letters(text):
return text.upper() == text.lower()
Como una estructura de datos en memoria, por ejemplo:
{ ''func_name'': ''has_no_letters'',
''num_args'': 1,
''kwargs'': [],
''codez'': [
(''get_attr'', ''tmp_a'', ''arg_0'', ''upper''), # tmp_a = arg_0.upper
(''func_call'', ''tmp_b'', ''tmp_a'', []), # tmp_b = tmp_a() # tmp_b = arg_0.upper()
(''get_attr'', ''tmp_c'', ''arg_0'', ''lower''),
(''func_call'', ''tmp_d'', ''tmp_c'', []),
(''get_global'', ''tmp_e'', ''==''),
(''func_call'', ''tmp_f'', ''tmp_e'', [''tmp_b'', ''tmp_d'']),
(''return'', ''tmp_f''),
]
}
Ahora, escribamos un intérprete que ejecute esta estructura de datos en memoria.
Discutamos los beneficios de esto sobre los intérpretes de texto directo, y luego los beneficios sobre la compilación a código de máquina.
Los beneficios de las máquinas virtuales sobre los intérpretes de texto directo
- El sistema VM le da todos los errores de sintaxis antes de ejecutar el código.
- Al evaluar un bucle, un sistema VM no analiza el código fuente cada vez que se ejecuta.
- Hacer que la máquina virtual sea más rápida que el intérprete de texto directo.
- Por lo tanto, el intérprete directo corre más lento con el nombre largo de la variable y más rápido con los nombres cortos de la variable. Esto anima a las personas a escribir código de estilo matemático de mala calidad como
wt(f, d(o, e), s) <= th(i, s) + cr(a, p * d + o)
Los beneficios de las máquinas virtuales sobre la compilación a código de máquina
- La estructura de datos en memoria que describe el programa, o el "código VM", probablemente será mucho más compacta que el código de máquina completo que hace lo mismo una y otra vez para cada línea de código original. Esto hará que el sistema VM se ejecute más rápido porque será necesario recuperar menos "instrucciones" de la memoria.
- Crear una máquina virtual es mucho más simple que crear un compilador a código de máquina. Probablemente pueda hacer esto ahora sin siquiera saber ningún código de ensamblador / máquina.
Una máquina virtual (VM) es en realidad una herramienta para que un diseñador de lenguaje evite cierta complejidad al escribir la implementación de un lenguaje.
Básicamente es una especificación de una computadora virtual y cómo cada pieza de dicha computadora interactuará con la otra. Puede codificar algunas suposiciones en esta especificación que pueden ser usadas por el idioma actual o no.
En esta especificación, generalmente se define cómo funcionan los procesadores / procesadores, cómo funciona la memoria, qué barreras de lectura / escritura son posibles, etc., y un lenguaje ensamblador más simple para interactuar con él.
El idioma final generalmente se traduce (compila) de los archivos de texto que está escribiendo en una representación escrita para esa máquina.
Esto tiene algunas ventajas:
- se desacopla el lenguaje de una arquitectura de hardware específica
- Por lo general te permite controlar lo que sucede.
- Diferentes personas pueden portar a una arquitectura diferente.
- Tienes más información para permitirte optimizar el código.
- etc.
También está el factor de frescor: Look Ma i hizo una máquina virtual :).
Una máquina virtual es básicamente un intérprete que interpreta un lenguaje más cercano al código de la máquina. Cuando la máquina real interpreta el código de máquina real, la máquina virtual interpreta un código de máquina inventado. Algunos VM-s interpretan el código de máquina de una computadora real, estos se llaman emuladores.
Es más fácil escribir un intérprete para un lenguaje simple de tipo ensamblador, y luego para el lenguaje completo de alto nivel. Además, muchas construcciones de código de alto nivel a menudo son simplemente azúcar sintáctica sobre algunos principios básicos. Por lo tanto, es más fácil escribir un compilador que traduce todos esos conceptos complejos al lenguaje VM simple, de modo que no tenemos que escribir un intérprete complejo, pero podemos hacerlo con uno simple (una VM). Y luego tienes más tiempo para optimizar la máquina virtual.
Básicamente, así es como se implementan la mayoría de los idiomas en estos días (que no se compilan en código de máquina real).
El intérprete (VM) y el compilador pueden ser programas separados (como java
y javac
), o pueden ser solo un programa (como con Ruby o Python).