(Dies ist eine extrem neue Frage).
Ich habe ein wenig über virtuelle Maschinen gelernt.
Es stellte sich heraus, dass viele von ihnen sehr ähnlich wie physische oder theoretische Computer konzipiert sind.
Ich habe gelesen, dass die JVM zum Beispiel eine "Stapelmaschine" ist. Das bedeutet (und korrigiert mich, wenn ich mich irre), dass es den gesamten 'temporären Speicher' auf einem Stapel speichert und Operationen auf diesem Stapel für alle seine Opcodes ausführt.
Zum Beispiel wird der Quellcode 2 + 3
in Bytecode übersetzt, ähnlich wie:
push 2
push 3
add
Meine Frage lautet:
JVMs werden wahrscheinlich mit C / C ++ und dergleichen geschrieben. Wenn ja, warum führt die JVM den folgenden C-Code nicht aus: 2 + 3
..? Ich meine, warum braucht es einen Stack oder in anderen VMs "Registern" - wie in einem physischen Computer?
Die zugrunde liegende physische CPU übernimmt dies alles. Warum führen VM-Writer den interpretierten Bytecode nicht einfach mit "üblichen" Anweisungen in der Sprache aus, mit der die VM programmiert ist?
Warum müssen VMs Hardware emulieren, wenn die eigentliche Hardware dies bereits für uns erledigt?
Wieder sehr neue Fragen. Danke für Ihre Hilfe
quelle
printf("hi");
dies als VM betrachtet? Es gibt keine "Stapel" oder "Register" und so weiter.Antworten:
Eine Maschine, ob virtuell oder nicht, benötigt ein Berechnungsmodell, das beschreibt, wie die Berechnung auf ihr ausgeführt wird. Per Definition implementiert es, sobald es berechnet wird, ein Rechenmodell. Die Frage ist dann: Welches Modell sollen wir für unsere VM wählen? Physische Maschinen sind durch die Möglichkeiten eingeschränkt, die Hardware effektiv und effizient bietet. Wie Sie jedoch bemerken, gibt es für virtuelle Maschinen keine derartigen Einschränkungen. Sie werden in Software unter Verwendung beliebig hoher Sprachen definiert.
Tatsächlich gibt es virtuelle Maschinen auf hohem Niveau, wie Sie beschreiben. Sie werden Programmiersprachen genannt . Der C-Standard zum Beispiel widmet den Großteil seiner Seiten der Definition eines Modells für die sogenannte "C-abstrakte Maschine", das beschreibt, wie sich C-Programme verhalten, und erweitert (als-ob-Regel), wie ein konformer C-Compiler (oder -Interpreter) arbeitet. sollte Verhalten.
Natürlich nennen wir das normalerweise keine virtuelle Maschine. Unter einer VM versteht man normalerweise eine niedrigere Ebene, die näher an der Hardware liegt, nicht direkt programmiert werden soll und so konzipiert ist, dass sie effizient ausgeführt werden kann. Diese Auswahlverzerrung bedeutet, dass etwas, das zusammensetzbaren Code auf hoher Ebene akzeptiert (wie das, was Sie beschreiben), nicht als VM angesehen wird, da Code auf hoher Ebene ausgeführt wird.
Aber um auf den Punkt zu kommen, hier sind einige Gründe, eine VM (wie in, etwas, auf das ein Bytecode-Compiler abzielt) auf Registerbasis oder dergleichen zu machen. Stapel- und Registriermaschinen sind extrem einfach. Es gibt eine Abfolge von Anweisungen, einen Status und eine Semantik für jede Anweisung (eine Funktion Status -> Status). Keine komplexen Baumreduzierungen, keine Operatorpräzision. Das Parsen, Analysieren und Ausführen ist sehr einfach, da es sich um eine minimale Sprache handelt (syntaktischer Zucker wird wegkompiliert) und so konzipiert ist, dass sie eher maschinell als vom Menschen gelesen werden kann.
Im Gegensatz dazu ist das Parsen selbst der einfachsten C-ähnlichen Sprachen ziemlich schwierig, und das Ausführen erfordert nicht-lokale Analysen wie das Überprüfen und Weitergeben von Typen, das Auflösen von Überladungen, das Verwalten einer Symboltabelle, das Auflösen von Zeichenfolgen- IDs und das Umwandeln von linearem Text in einen prioritätsgesteuerten AST , und so weiter. Es baut auf Konzepten auf, die für den Menschen selbstverständlich sind, die jedoch von Maschinen akribisch rückentwickelt werden müssen.
JVM-Bytecode wird beispielsweise von ausgegeben
javac
. Es muss praktisch nie von Menschen gelesen oder geschrieben werden, daher ist es normal, es auf den Verbrauch durch Maschinen abzustimmen. Wenn Sie es für den Menschen optimiert haben, würde die JVM bei jedem Start den Code lesen, analysieren und dann in eine Zwischendarstellung konvertieren, die sowieso so einem vereinfachten Maschinenmodell ähnelt . Könnte auch den mittleren Mann ausschneiden.quelle
System.out.println("hi");
Kompilieren einer Anweisung auf einem Stapel,int a = 7
Kompilieren einer Anweisung auf dem Stapel usw.) die Ausführung des Programms einfacher und effizienter macht?2 + 3
kompiliert wirdpush 2 push 3 add
. Deradd
Schritt am Ende wird ohnehin von der JVM ausgeführt, indem der C-Code ausgeführt wird2 + 3
. Es gibt keine andere Möglichkeit für die Programmierer der JVM, dies zu tun. Warum kompilieren Sie es nicht2 + 3
und lassen Sie die JVM sofort den C-Code ausführen2 + 3
(vorausgesetzt, er ist in C geschrieben)?2 + 3
in den JVM-Quellcode schreiben, da die JVM mit jedem Programm zusammenarbeiten muss, das Operationen in beliebiger Reihenfolge ausführt . Die Erstellung von C-Quellcode und die Verlagerung auf eine C-Implementierung führen zu demselben Problem in der C-Implementierung (und können nicht einfach und geschweige denn effizient durchgeführt werden). Es muss eine Datenstruktur geben, die das Programm beschreibt, damit es interpretiert und JIT-kompiliert werden kann, und "von Menschen lesbarer Quellcode" ist aus den oben genannten Gründen eine schreckliche Wahl der Datenstruktur.a + b
? Die hinzuzufügenden Werte stammen dann nicht voni.argument{1,2}
, sondern werden aus lokalen Variablen geladen. Was istfrobnicate(x[i]) + (Foo.bar() * 2)
? Bei Verwendung dieses Entwurfs gibt es nur eineadd
Operation (fürint
) und sie funktioniert unabhängig davon, wie die Addenden berechnet wurden. Außerdem wäre eine Anweisung, die nur ganzzahlige Literale hinzufügt , sinnlos: Das Ergebnis könnte genauso gut vorberechnet werden (dh stattdessenadd(2,3)
sollte es seinpush(5)
).Diese Antwort konzentriert sich auf die JVM, gilt jedoch für jede VM.
Dies ist nicht der Fall, macht die VM jedoch viel einfacher und portabler: Eine VM, die Hardware emuliert, kann dasselbe Rechenmodell wie jede andere Hardware-CPU verwenden.
Insbesondere die JVM wurde mit Blick auf die Portabilität entwickelt. Sie wurde sogar so entwickelt, dass sie sogar in Hardware implementiert werden kann (das ist heutzutage kaum zu glauben, aber der Ursprung von Java lag in der eingebetteten Welt - speziell bei Controllern für interaktives Fernsehen ).
Wenn Sie ein solches Ziel haben, ist es wünschenswert, dass die VM so nah wie möglich an einer physischen Maschine arbeitet, da die Übersetzung in tatsächlichen Maschinencode einfacher und damit schneller wird. Sobald Sie die Opcodes der VM haben, müssen Sie theoretisch nur noch die Opcodes der CPU übersetzen, auf der das Programm tatsächlich ausgeführt wird. In der Praxis ist das nicht ganz so einfach.
Die Verwendung eines stapelbasierten virtuellen Maschinenmodells hat den Vorteil, dass es leicht auf Register- und Stapelmaschinen übertragen werden kann, während das Gegenteil nicht unbedingt der Fall ist. Eine auf Registern basierende VM müsste Annahmen über die Anzahl der Register, die Größe der Register usw. treffen. Bei einer Stapelmaschine sind solche Annahmen nicht erforderlich.
Nun, das ist, was solche VMs tun, sie interpretieren Bytecode. Sogar die JVM tut dies tatsächlich, zumindest bevor JIT (Just-in-Time) einsetzt: Sie interpretiert die Bytecodes und führt die Anweisungen in der Sprache aus, in der die JVM geschrieben wurde (normalerweise C oder C ++), aber es gibt sogar eine geschriebene in JavaScript, Doppio ). Beachten Sie jedoch, dass selbst solche Anweisungen von einem Compiler in Maschinencode übersetzt wurden und dem, was der Java-Compiler erzeugt, sehr ähnlich sehen - sie verwenden nämlich Register und den Stack, um ihre Arbeit auszuführen. Beachten Sie, dass die Verwendung von "interpretierten" und "kompilierten" Sprachen an dieser Stelle etwas unscharf wird.
quelle
Warum müssen VMs „Stapelmaschinen“ oder „Registriermaschinen“ usw. sein?
Sie nicht. Wenn Sie eine virtuelle Maschine benötigen, kann dies alles sein.
Die vorhandenen virtuellen Maschinen haben sich als Lösungen für die folgenden Situationen erwiesen: Eine wirklich brillante Idee ist mir eingefallen, ich habe eine neue Programmiersprache erfunden! Aber ich muss Code generieren. (Was für eine langweilige Aufgabe!) Aber ich möchte keinen i8086-Code generieren, weil er hässlich ist, und ich möchte keinen 68k-Code generieren, weil alle anderen Intel verwenden. Es gibt auch VAX, aber ich habe kein VAX, weder einen Computer noch ein VAX-Buch. Daher werde ich Code für einen Prozessor generieren, der physikalisch nicht existiert, und diesen Prozessor in Software implementieren. Die Spezifikation dieser VM wird ein Kapitel in meiner Arbeit bilden. Theoretisch wird es möglich sein, es in den nativen Code eines beliebigen Prozessors zu kompilieren, aber das werde ich nicht sein.
Auf der anderen Seite wird die Notation "2 + 3" wahrscheinlich in absehbarer Zeit nicht von VMs verwendet, da sie eine Menge Transformationen erfordert, bevor etwas ausgeführt werden kann.
quelle
Um die eigentliche Frage zu beantworten, die gestellt wurde. Der Begriff "virtuelle MASCHINE" bedeutet, dass ALLE Software / Hardware simuliert / emuliert wird. Wenn Sie zur Ausführung der Anweisungen die zugrunde liegende Software / Hardware verwenden, verfügen Sie nicht über eine VM, sondern über einen Compiler / Interpreter.
quelle