virtuales ventajas una tipos requisitos para maquinas maquina las instalar gratis ejemplos desventajas caracteristicas compiler-construction vm-implementation

compiler-construction - ventajas - tipos de maquinas virtuales



¿Por qué son necesarias las máquinas virtuales? (10)

Estaba leyendo esta pregunta para descubrir las diferencias entre Java Virtual Machine y .NET CLR, y la respuesta de Benji me hizo preguntarme por qué las máquinas virtuales son necesarias en primer lugar.

Desde mi comprensión de la explicación de Benji, el compilador JIT de una máquina virtual interpreta el código intermedio en el código ensamblador real que se ejecuta en la CPU. La razón por la que tiene que hacer esto es porque las CPU a menudo tienen diferentes números de registros y, según Benji, "algunos registros son de propósito especial, y cada instrucción espera sus operandos en diferentes registros". Esto tiene sentido entonces que hay una necesidad de un intérprete intermediario como la Máquina Virtual para que el mismo código se pueda ejecutar en cualquier CPU.

Pero, si ese es el caso, entonces lo que no entiendo es por qué el código C o C ++ compilado en código máquina puede ejecutarse en cualquier computadora, siempre que sea el SO correcto. ¿Por qué entonces un programa de C que compilé en mi máquina con Windows utilizando un Pentium podría ejecutarse en mi otra máquina de Windows usando un AMD?

Si el código C se puede ejecutar en cualquier CPU, ¿cuál es el propósito de la máquina virtual? ¿Es así que el mismo código se puede ejecutar en cualquier sistema operativo? Sé que Java tiene versiones de VM en prácticamente cualquier sistema operativo, pero ¿hay un CLR para otros sistemas operativos además de Windows?

¿O hay algo más que me estoy perdiendo? ¿El sistema operativo realiza alguna otra interpretación del código ensamblador que se ejecuta para adaptarlo a la CPU particular o algo así?

Tengo bastante curiosidad sobre cómo funciona todo esto, por lo que una explicación clara sería muy apreciada.

Nota: El motivo por el que no solo publiqué mis consultas como comentarios en la pregunta de JVM vs. CLR es porque aún no tengo suficientes puntos para publicar comentarios = b.

Editar: ¡Gracias por todas las excelentes respuestas! Parece que lo que me faltaba era que, aunque todos los procesadores tienen diferencias, existe una estandarización común, principalmente la arquitectura X86, que proporciona un conjunto suficientemente grande de características comunes para que el código C compilado en un procesador X86 funcione en su mayor parte en otro procesador X86. Esto amplía la justificación para Máquinas Virtuales, sin mencionar que me olvidé de la importancia de la recolección de basura.


La mayoría de los compiladores, incluso los compiladores de códigos nativos, usan algún tipo de lenguaje intermedio.

Esto se hace principalmente para reducir los costos de construcción del compilador. Hay muchos (N) lenguajes de programación en el mundo. También hay muchas (M) plataformas de hardware en el mundo. Si los compiladores funcionaran sin utilizar un lenguaje intermedio, la cantidad total de "compiladores" que necesitarían escribirse para admitir todos los idiomas en todas las plataformas de hardware sería N * M.

Sin embargo, al definir un lenguaje intermedio y dividir un compilador en 2 partes, una interfaz y un servidor, compilando el código fuente en IL y el servidor compilando IL en el código de máquina, puede salirse con la única escritura Compiladores N + M. Esto termina siendo un gran ahorro de costos.

La gran diferencia entre los compiladores CLR / JVM y los compiladores de códigos nativos es la forma en que los compiladores frontales y posteriores están vinculados entre sí. En un compilador de código nativo, los dos componentes generalmente se combinan en el mismo ejecutable, y ambos se ejecutan cuando el programador golpea "compilar" en el IDE.

Con los compiladores CLR / JVM, el extremo frontal y el posterior se ejecutan en diferentes momentos. La interfaz se ejecuta en tiempo de compilación, produciendo IL que en realidad se envía a los clientes. El back-end se incorpora en un componente separado que se invoca en el tiempo de ejecución.

Por lo tanto, esto plantea la pregunta alternativa, "¿Cuáles son los beneficios de retrasar la compilación de back-end hasta el tiempo de ejecución"?

La respuesta es, depende".

Al retrasar la compilación de back-end hasta el tiempo de ejecución, es posible enviar un conjunto de archivos binarios que se pueden ejecutar en múltiples plataformas de hardware. También posibilita que los programas aprovechen las mejoras en la tecnología de compilación de back-end sin ser redistribuidos. También puede proporcionar una base para implementar eficientemente muchas características de lenguaje dinámico. Finalmente, ofrece la capacidad de introducir restricciones de seguridad y confiabilidad entre bibliotecas compiladas dinámicamente (dlls) compiladas por separado, que no es posible con la compilación de códigos máquina por adelantado.

Sin embargo, también hay retrocesos. El análisis necesario para implementar optimizaciones extensas del compilador puede ser costoso. Esto significa que los back ends de "JIT" a menudo harán menos optimizaciones que los back-end anteriores. Esto puede perjudicar el rendimiento. Además, la necesidad de invocar el compilador en el tiempo de ejecución también aumenta el tiempo necesario para cargar programas. Los programas generados con compiladores "iniciales" no tienen esos problemas.


Sé que Java tiene versiones de VM en prácticamente cualquier sistema operativo, pero ¿hay un CLR para otros sistemas operativos además de Windows?

Mono


Básicamente, permite ''código administrado'', lo que significa exactamente lo que dice: la máquina virtual administra el código mientras se ejecuta. Tres de los principales beneficios de esto son la compilación justo a tiempo, punteros administrados / recolección de basura y control de seguridad.

Para la compilación justo a tiempo, la máquina virtual observa el código ejecutarse y, a medida que el código se ejecuta más a menudo, se vuelve a optimizar para que se ejecute más rápido. No puedes hacer esto con un código nativo.

Los punteros administrados también son más fáciles de optimizar porque la máquina virtual los rastrea a medida que avanzan, administrándolos de diferentes maneras según su tamaño y duración. Es difícil hacer esto en C ++ porque realmente no se puede decir a dónde va un puntero simplemente leyendo el código.

La seguridad se explica por sí misma, la máquina virtual impide que el código haga cosas que no debería porque está mirando. Personalmente, creo que esa es probablemente la razón más importante por la cual Microsoft eligió el código administrado para C #.

Básicamente, mi punto es que, debido a que la máquina virtual puede ver el código tal como está, puede hacer cosas que facilitan la vida del programador y hacen que el código sea más rápido.


Creo que la premisa de su pregunta es válida; ciertamente no es el primero en hacer esta pregunta. Así que echa un vistazo a http://llvm.org para ver un enfoque alternativo (que ahora es un proyecto que se ejecuta? O patrocinado por Apple)


De una manera muy simplificada, eso se debe a que Intel y AMD implementan el mismo lenguaje ensamblador, con el mismo número de registros, etc, etc.

Entonces su compilador de C compila el código para trabajar en Linux. Ese ensamblaje está utilizando un ABI de Linux, por lo que siempre y cuando el programa de compilación se ejecute en Linux, en el ensamblaje x86 y la firma de función correcta, todo estará muy bien.

Ahora intente tomar ese código compilado y péguelo, digamos Linux / PPC (por ejemplo, Linux en un iBook antiguo). Eso no va a funcionar. Donde como un programa Java lo haría porque la JVM se ha implementado en la plataforma Linux / PPC.

El lenguaje de ensamblaje hoy en día es básicamente otra interfaz a la que un programador puede programar. x86 (32 bits) le permite acceder a eax, ebx, ecx, edx para registros enteros de propósito general y f00-f07 para coma flotante. Detrás de escena, la CPU en realidad tiene cientos de registros más, y mezcló esas cosas para exprimir el rendimiento.


En primer lugar, el código de máquina no es la forma más baja de instrucciones para una CPU. Los CPUS x86 de hoy en día interpretan el conjunto de instrucciones X86 en otro formato interno utilizando microcódigo. Las únicas personas que realmente programan el microcódigo son los tipos de ingenieros de desarrollo de chips, quienes fiel y sin dolor emulan el chip de instrucción heredado x86 para lograr el máximo rendimiento utilizando las tecnologías actuales.

Los tipos de desarrollador siempre han estado agregando capas adicionales de abstracciones debido a la potencia y las características que aportan. Después de todas las mejores abstracciones, las nuevas aplicaciones se pueden escribir de forma más rápida y confiable. A las empresas no les importa qué o cómo codifican parece que solo quieren que el trabajo se realice de manera confiable y rápida. ¿Realmente importa si la versión C de una aplicación tarda unos pocos milisegundos menos, pero termina tomando el doble de tiempo para desarrollarse?

La cuestión de la velocidad es casi un argumento, ya que muchas aplicaciones empresariales que sirven a millones de personas están escritas en plataformas / idiomas como Java, por ejemplo, GMail, GMaps. Olvídate de qué idioma / plataforma es más rápido. Lo que es más importante es que use los algoritmos correctos y escriba un código eficiente y realice el trabajo.


Los procesadores AMD e Intel tienen arquitectura x86, si desea ejecutar el programa c / c ++ en una arquitectura diferente, debe usar un compilador para esa arquitectura, el mismo ejecutable binario no se ejecutará en arquitecturas de procesador diferentes.


Los procesadores AMD e Intel usan el mismo conjunto de instrucciones y la misma arquitectura de máquina (desde el punto de vista de la ejecución del código máquina).

Los compiladores C y C ++ compilan código máquina, con encabezados apropiados para el sistema operativo al que están destinados. Una vez compilados, dejan de asociarse de cualquier manera, forma o forma con el lenguaje en el que fueron compilados y son simplemente ejecutables binarios. (hay artefactos que pueden mostrar de qué lenguaje se compiló, pero ese no es el punto aquí)

Una vez compilados, están asociados a la máquina (X86, el conjunto de instrucciones intel y amd y la arquitectura) y el sistema operativo.

Es por eso que pueden ejecutarse en cualquier máquina x86 compatible, y cualquier sistema operativo compatible (win95 a través de winvista, para algún software).

Sin embargo, no pueden ejecutarse en una máquina OSX, incluso si se ejecuta en un procesador Intel: el binario no es compatible a menos que ejecute software de emulación adicional (como paralelos o una VM con Windows).

Además, si desea ejecutarlos en un procesador ARM, MIPS o PowerPC, debe ejecutar un emulador de conjunto de instrucciones de máquina completo que interprete el código de máquina binario de X86 en cualquier máquina en la que lo esté ejecutando.

Contraste eso con .NET.

La máquina virtual .NET está fabricada como si hubiera procesadores mucho mejores en el mundo: procesadores que entienden los objetos, la asignación de memoria y la recolección de basura, y otros constructos de alto nivel. Es una máquina muy compleja y no se puede construir directamente en silicio ahora (con buen rendimiento), pero se puede escribir un emulador que le permita ejecutarse en cualquier procesador existente.

De repente, puede escribir un emulador específico de máquina para cualquier procesador en el que desee ejecutar .NET, y luego se puede ejecutar CUALQUIER programa .NET. No hay necesidad de preocuparse por el sistema operativo o la arquitectura subyacente de la CPU: si hay una máquina virtual .NET, se ejecutará el software.

Pero vayamos un poco más allá: una vez que tenga este lenguaje común, ¿por qué no hacer compiladores que conviertan cualquier otro lenguaje escrito en él?

Así que ahora puede tener un compilador C, C #, C ++, Java, javascript, Basic, python, lua o cualquier otro que convierta código escrito para que se ejecute en esta máquina virtual.

Has desasociado la máquina del idioma en 2 grados, y con poco trabajo permites que cualquiera escriba cualquier código y lo ejecute en cualquier máquina, siempre que exista un compilador y una VM para asignar los dos grados de separación. .

Si todavía se está preguntando por qué esto es algo bueno, considere las primeras máquinas con DOS, y cuál fue la verdadera contribución de Microsoft al mundo:

Autocad tuvo que escribir controladores para cada impresora en la que pudieran imprimir. Lo mismo hizo Lotus 1-2-3. De hecho, si quería imprimir su software, tenía que escribir sus propios controladores. Si había 10 impresoras y 10 programas, entonces 100 piezas diferentes de esencialmente el mismo código tenían que escribirse por separado e independientemente.

Lo que Windows 3.1 intentó lograr (junto con GEM y muchas otras capas de abstracción) es hacer que el fabricante de la impresora haya escrito un controlador para su impresora y el programador haya escrito un controlador para la clase de impresora de Windows.

Ahora, con 10 programas y 10 impresoras, solo se deben escribir 20 códigos, y como el lado Microsoft del código era el mismo para todos, los ejemplos de MS significaban que tenía muy poco trabajo por hacer.

Ahora, un programa no estaba restringido solo a las 10 impresoras que eligieron para admitir, sino a todas las impresoras cuyos fabricantes proporcionaban controladores en Windows.

El mismo problema está ocurriendo en el desarrollo de aplicaciones. En realidad, hay aplicaciones geniales que no puedo usar porque no utilizo un MAC. Hay un montón de duplicaciones (¿cuántos procesadores de palabras de clase mundial realmente necesitamos?).

Java tenía la intención de solucionar esto, pero tenía muchas limitaciones, algunas de las cuales no estaban realmente resueltas.

.NET está más cerca, pero nadie está desarrollando máquinas virtuales de clase mundial para plataformas que no sean Windows (el mono está tan cerca ... pero aún no está allí).

Entonces ... Es por eso que necesitamos máquinas virtuales. Porque no quiero limitarme a una audiencia más pequeña simplemente porque eligieron una combinación de sistema operativo / máquina diferente a la mía.

-Adán


Su suposición de que el código C puede ejecutarse en cualquier procesador es incorrecto. Hay cosas como registros y endianness que harán que los programas compilados C no funcionen en absoluto en una plataforma, mientras que podría funcionar en otra.

Sin embargo, hay ciertas similitudes que los procesadores comparten, por ejemplo, los procesadores Intel x86 y los procesadores AMD comparten un conjunto suficientemente grande de propiedades que la mayoría de los códigos compilados contra uno se ejecutarán en el otro. Sin embargo, si desea usar propiedades específicas del procesador, necesita un compilador o conjunto de bibliotecas que lo haga por usted.

En cuanto a por qué querría una máquina virtual, más allá de la afirmación de que manejará las diferencias en los procesadores para usted, también existe el hecho de que las máquinas virtuales ofrecen servicios para codificar que no están disponibles para los programas compilados en C ++ (no administrados) hoy.

El servicio más destacado ofrecido es la recolección de basura, ofrecido por CLR y JVM. Ambas máquinas virtuales le ofrecen este servicio de forma gratuita. Ellos administran la memoria para ti.

Cosas como comprobación de límites, violaciones de acceso (aunque aún son posibles, son extremadamente difíciles) también se ofrecen.

CLR también ofrece una forma de seguridad de código para usted.

Ninguno de estos se ofrece como parte del entorno de tiempo de ejecución básico para varios otros idiomas que no operan con una máquina virtual.

Puede obtener algunos de ellos mediante el uso de bibliotecas, pero luego eso lo obliga a utilizar un patrón de uso con la biblioteca, mientras que en los servicios .NET y Java que se le ofrecen a través de CLR y JVM son consistentes en su acceso.


Tienes razón en tu análisis, java o C # podrían haberse diseñado para compilarse directamente para ejecutar en cualquier máquina, y probablemente serían más rápidos si lo hicieran. Pero el enfoque de máquina virtual brinda control completo del entorno en el que se ejecuta el código, la máquina virtual crea un entorno limitado seguro que solo permite comandos con el acceso de seguridad correcto para realizar un código potencialmente dañino, como cambiar la contraseña o actualizar un sector de inicio HD. Hay muchos otros beneficios, pero esa es la razón más importante. No puede obtener un en C # ...