Wozu dient die Konvertierung von Quellcode in Java-Bytecode?

37

Wenn man verschiedene JVMs für verschiedene Architekturen benötigt, kann ich nicht herausfinden, welche Logik hinter der Einführung dieses Konzepts steckt. In anderen Sprachen benötigen wir unterschiedliche Compiler für unterschiedliche Maschinen, aber in Java benötigen wir unterschiedliche JVMs. Welche Logik steckt also hinter der Einführung des Konzepts einer JVM oder dieses zusätzlichen Schritts?

Pranjal Kumar
quelle
1
Mögliches Duplikat der Kompilierung zu Bytecode vs Maschinencode
Mücke
12
@gnat: Eigentlich ist das kein Duplikat. Dies ist "Source vs Byte Code", also nur die erste Transformation. In der Sprache ist dies Javascript im Vergleich zu Java. Ihr Link wäre C ++ gegen Java.
MSalters
2
Möchten Sie lieber einen einfachen Bytecode-Interpreter für die 50 Appliance-Modelle schreiben, denen Sie digitale Codierung zum Aktualisieren hinzufügen, oder 50 Compiler für 50 verschiedene Hardware. Java wurde ursprünglich für Geräte und Maschinen entwickelt. Das war sein starker Anzug. Denken Sie daran, wenn Sie diese Antworten lesen, da Java heutzutage keinen wirklichen Vorteil hat (aufgrund der Ineffizienz des Interpretationsprozesses). Es ist nur ein Modell, das wir weiterhin verwenden.
Die große Ente
1
Sie scheinen nicht zu verstehen, was eine virtuelle Maschine ist . Es ist eine Maschine. Es könnte in Hardware mit nativen Code-Compilern implementiert werden (und im Fall der JVM war dies der Fall). Der "virtuelle" Teil ist hier wichtig: Sie emulieren im Wesentlichen diese Architektur über einer anderen. Angenommen, ich habe einen 8088-Emulator für x86 geschrieben. Sie werden den alten 8088-Code nicht auf x86 portieren, sondern nur auf der emulierten Plattform ausführen. Die JVM ist eine Maschine, die Sie wie jede andere anvisieren. Der Unterschied besteht darin, dass sie auf den anderen Plattformen ausgeführt wird.
Jared Smith
7
@TheGreatDuck Dolmetschprozess? Heutzutage kompilieren die meisten JVMs Just-in-Time-Code. Ganz zu schweigen davon, dass "Interpretation" heutzutage ein ziemlich weit gefasster Begriff ist. Die CPU selbst "interpretiert" den x86-Code lediglich in ihren eigenen internen Mikrocode und verbessert damit die Effizienz. Die neuesten Intel-CPUs eignen sich auch hervorragend für Dolmetscher im Allgemeinen (obwohl Sie natürlich Benchmarks finden, mit denen Sie beweisen können, was Sie beweisen möchten).
Luaan

Antworten:

79

Die Logik ist, dass JVM-Bytecode viel einfacher ist als Java-Quellcode.

Man kann sich Compiler auf einer sehr abstrakten Ebene mit drei grundlegenden Teilen vorstellen: Parsen, semantische Analyse und Codegenerierung.

Beim Parsen wird der Code gelesen und in eine Baumdarstellung im Speicher des Compilers umgewandelt. Semantische Analyse ist der Teil, in dem dieser Baum analysiert wird, herausgefunden wird, was er bedeutet, und alle Konstrukte auf hoher Ebene bis zu Konstrukten auf niedrigerer Ebene vereinfacht werden. Bei der Codegenerierung wird der vereinfachte Baum in eine flache Ausgabe geschrieben.

Mit einer Bytecode-Datei wird die Parsing-Phase erheblich vereinfacht, da sie nicht in einer rekursiven (baumstrukturierten) Quellsprache, sondern im gleichen Flat-Byte-Stream-Format wie die JIT geschrieben wird. Außerdem hat der Java-Compiler (oder ein Compiler in einer anderen Sprache) bereits einen Großteil der umfangreichen semantischen Analyse durchgeführt. Sie müssen also nur den Code per Stream lesen, minimales Parsing und minimale semantische Analyse durchführen und dann den Code generieren.

Dies macht die Aufgabe, die das JIT zu erfüllen hat, viel einfacher und daher viel schneller, während die Metadaten und semantischen Informationen auf hoher Ebene erhalten bleiben, die das theoretische Schreiben von plattformübergreifendem Code aus einer Quelle ermöglichen.

Mason Wheeler
quelle
7
Einige der anderen frühen Versuche, Applets zu verteilen, wie z. B. SafeTCL, verteilten tatsächlich Quellcode. Die Verwendung eines einfachen und genau festgelegten Bytecodes durch Java macht die Überprüfung des Programms viel einfacher und das war das schwierige Problem, das gelöst wurde. Bytecodes wie p-Code waren bereits als Teil der Lösung des Portabilitätsproblems bekannt (und ANDF befand sich wahrscheinlich zu diesem Zeitpunkt in der Entwicklung).
Toby Speight
9
Genau. Java-Startzeiten sind aufgrund des Bytecode-> Maschinencodeschritts bereits ein Problem. Führen Sie javac in Ihrem (nicht trivialen) Projekt aus und stellen Sie sich dann vor, Sie würden den gesamten Java-> Maschinencode bei jedem Start ausführen.
Paul Draper
24
Es hat einen weiteren großen Vorteil: Wenn wir eines Tages alle auf eine hypothetische neue Sprache umstellen möchten - nennen wir es "Scala" -, müssen wir nur einen Scala -> Bytecode-Compiler schreiben und nicht Dutzende von Scala -> Maschinencode Compiler. Als Bonus erhalten wir alle plattformspezifischen Optimierungen der JVM kostenlos.
BlueRaja - Danny Pflughoeft
8
Einige Dinge sind im JVM-Bytecode immer noch nicht möglich, z. B. die Tail-Call-Optimierung. Ich erinnere mich, dass dies eine funktionale Sprache stark beeinträchtigt, die zu JVM kompiliert wird.
JDługosz
8
@ JDługosz rechts: JVM unterwirft leider einige Einschränkungen / Design-Idiome, die, wenn Sie aus einer imperativen Sprache kommen, zwar vollkommen natürlich sind, aber zu einem künstlichen Hindernis werden können, wenn Sie einen Compiler für eine Sprache schreiben möchten, die grundlegend funktioniert anders. Ich halte LLVM daher für ein besseres Ziel, wenn es um die Wiederverwendung von Arbeit in zukünftigen Sprachen geht - es hat auch Einschränkungen, aber sie stimmen mehr oder weniger mit den Einschränkungen überein, die derzeitige Prozessoren (und wahrscheinlich in der Zukunft) ohnehin haben.
Leftaroundabout
27

Intermediate-Darstellungen verschiedener Art sind im Compiler / Runtime-Design aus mehreren Gründen immer häufiger anzutreffen.

In Javas Fall war der Hauptgrund anfangs wahrscheinlich die Portabilität : Java wurde anfangs stark als "Write Once, Run Anywhere" vermarktet. Sie können dies zwar erreichen, indem Sie den Quellcode verteilen und verschiedene Compiler für verschiedene Plattformen verwenden, dies hat jedoch einige Nachteile:

  • Compiler sind komplexe Werkzeuge, die alle Bequemlichkeitssyntaxen der Sprache verstehen müssen. Bytecode kann eine einfachere Sprache sein, da es sich eher um maschinenausführbaren Code als um eine von Menschen lesbare Quelle handelt. das heisst:
    • Die Kompilierung ist möglicherweise langsamer als die Ausführung von Bytecode
    • Compiler, die auf unterschiedliche Plattformen abzielen, führen möglicherweise zu unterschiedlichem Verhalten oder können Sprachänderungen nicht nachvollziehen
    • Das Erstellen eines Compilers für eine neue Plattform ist viel schwieriger als das Erstellen einer VM (oder eines Compilers von Bytecode zu Native) für diese Plattform
  • das Verteilen von Quellcode ist nicht immer wünschenswert; Bytecode bietet einen gewissen Schutz gegen Reverse Engineering (obwohl es immer noch ziemlich einfach zu dekompilieren ist, wenn es nicht absichtlich verschleiert wird).

Weitere Vorteile einer Zwischendarstellung sind:

  • Optimierung , bei der Muster im Bytecode aufgespürt und zu schnelleren Entsprechungen kompiliert werden können, oder sogar für Sonderfälle während der Ausführung des Programms optimiert werden (mithilfe eines "JIT" - oder "Just In Time" -Compilers)
  • Interoperabilität zwischen mehreren Sprachen in derselben VM; Dies ist bei der JVM (z. B. Scala) populär geworden und das explizite Ziel des .net-Frameworks
IMSoP
quelle
1
Java war auch auf eingebettete Systeme ausgerichtet. In solchen Systemen hatte die Hardware verschiedene Einschränkungen in Bezug auf Speicher und CPU.
Laiv
Können Compliers so entwickelt werden, dass sie zuerst Java-Quellcode in Byte-Code und dann Byte-Code in Maschinencode kompilieren? Würde es die meisten Nachteile beseitigen, die Sie erwähnt haben?
Sher10ck
@ Sher10ck Ja, AFAIK kann durchaus einen Compiler schreiben, der JVM-Bytecode in Maschinenanweisungen für eine bestimmte Architektur statisch konvertiert. Es wäre jedoch nur sinnvoll, wenn die Leistung genug verbessert würde, um entweder den zusätzlichen Aufwand für den Distributor oder die zusätzliche Zeit für die erstmalige Verwendung für den Benutzer aufzuwiegen. Ein Embedded-System mit geringem Stromverbrauch könnte davon profitieren. Ein moderner PC, der viele verschiedene Programme herunterlädt und ausführt, ist mit einem gut abgestimmten JIT wahrscheinlich besser dran. Ich denke, Android geht irgendwo in diese Richtung, weiß aber keine Details.
IMSoP
8

Es hört sich so an, als würden Sie sich fragen, warum wir nicht nur Quellcode vertreiben. Lassen Sie mich diese Frage umkehren: Warum verteilen wir nicht einfach Maschinencode?

Die Antwort lautet hier eindeutig: Java geht von vornherein nicht davon aus, dass es weiß, auf welcher Maschine Ihr Code ausgeführt wird. Es kann sich um einen Desktop, einen Supercomputer, ein Telefon oder irgendetwas dazwischen und darüber hinaus handeln. Java lässt dem lokalen JVM-Compiler Raum, um seine Sache zu erledigen. Dies erhöht nicht nur die Portabilität Ihres Codes, sondern bietet auch den Vorteil, dass der Compiler beispielsweise die Möglichkeit hat, maschinenspezifische Optimierungen zu nutzen, falls vorhanden, oder zumindest funktionierenden Code zu erstellen, wenn dies nicht der Fall ist. Dinge wie SSE- Anweisungen oder Hardwarebeschleunigung können nur auf den Maschinen verwendet werden, die sie unterstützen.

In diesem Licht ist die Begründung für die Verwendung von Byte-Code gegenüber Roh-Quellcode klarer. Die Annäherung an die Maschinensprache ermöglicht es uns, einige der Vorteile von Maschinencode zu realisieren oder teilweise zu realisieren, wie zum Beispiel:

  • Schnellere Startzeiten, da ein Teil der Kompilierung und Analyse bereits erfolgt ist.
  • Sicherheit, da das Bytecode-Format einen eingebauten Mechanismus zum Signieren der Verteilungsdateien hat (Quelle könnte dies nach Konvention tun, aber der Mechanismus, um dies zu erreichen, ist nicht so eingebaut wie bei Bytecode).

Beachten Sie, dass ich eine schnellere Ausführung nicht erwähne. Sowohl Quellcode als auch Bytecode sind oder können (theoretisch) zur tatsächlichen Ausführung vollständig mit demselben Maschinencode kompiliert werden.

Darüber hinaus ermöglicht der Bytecode einige Verbesserungen gegenüber dem Maschinencode. Natürlich gibt es die Plattformunabhängigkeit und hardwarespezifische Optimierungen, die ich bereits erwähnt habe, aber es gibt auch Dinge wie die Wartung des JVM-Compilers, um aus altem Code neue Ausführungspfade zu erstellen. Dies kann sein, um Sicherheitsprobleme zu beheben, oder wenn neue Optimierungen entdeckt werden, oder um neue Hardwareanweisungen zu nutzen. In der Praxis kommt es selten vor, dass große Änderungen auf diese Weise vorgenommen werden, da dies Fehler aufdecken kann. Dies ist jedoch möglich und geschieht die ganze Zeit über auf kleine Weise.

Joel Coehoorn
quelle
8

Hier scheint es mindestens zwei verschiedene mögliche Fragen zu geben. Man geht wirklich um Compiler im Allgemeinen, wobei Java im Grunde nur ein Beispiel für das Genre ist. Die andere ist spezifischer für Java als die spezifischen Byte-Codes, die es verwendet.

Compiler im Allgemeinen

Betrachten wir zunächst die allgemeine Frage: Warum sollte ein Compiler beim Kompilieren von Quellcode eine Zwischendarstellung verwenden, um auf einem bestimmten Prozessor ausgeführt zu werden?

Komplexitätsreduzierung

Eine Antwort darauf ist ziemlich einfach: Es wandelt ein O (N * M) -Problem in ein O (N + M) -Problem um.

Wenn wir N Ausgangssprachen und M Ziele haben und jeder Compiler völlig unabhängig ist, brauchen wir N * M Compiler, um alle diese Ausgangssprachen in alle diese Ziele zu übersetzen (wobei ein "Ziel" so etwas wie eine Kombination von a ist Prozessor und Betriebssystem).

Wenn sich jedoch alle diese Compiler auf eine gemeinsame Zwischendarstellung einigen, können wir N Compiler-Frontends haben, die die Ausgangssprachen in die Zwischendarstellung übersetzen, und M Compiler-Backends, die die Zwischendarstellung in etwas übersetzen, das für ein bestimmtes Ziel geeignet ist.

Problemsegmentierung

Besser noch, es unterteilt das Problem in zwei mehr oder weniger exklusive Domänen. Leute, die sich mit Sprachdesign, Parsing und ähnlichen Dingen auskennen / auskennen, können sich auf Compiler-Frontends konzentrieren, während Leute, die sich mit Befehlssätzen, Prozessordesign und ähnlichen Dingen auskennen, sich auf das Backend konzentrieren können.

So haben wir zum Beispiel für LLVM viele Frontends für verschiedene Sprachen. Wir haben auch Backends für viele verschiedene Prozessoren. Ein Sprachtyp kann ein neues Frontend für seine Sprache schreiben und schnell viele Ziele unterstützen. Ein Prozessor-Typ kann ein neues Back-End für sein Ziel schreiben, ohne sich mit Sprachdesign, Parsen usw. zu befassen.

Die Trennung von Compilern in ein Front-End und ein Back-End mit einer Zwischendarstellung für die Kommunikation zwischen beiden ist mit Java nicht original. Es ist schon lange üblich (jedenfalls lange bevor Java hinzukam).

Verteilungsmodelle

Soweit Java diesbezüglich etwas Neues hinzufügte, befand es sich im Verteilungsmodell. Insbesondere wurden Compiler, obwohl sie intern lange Zeit in Front-End- und Back-End-Teile unterteilt waren, in der Regel als einzelnes Produkt vertrieben. Wenn Sie beispielsweise einen Microsoft C-Compiler gekauft haben, hatte dieser intern ein "C1" und ein "C2", die jeweils das Front-End und das Back-End waren. Sie haben jedoch nur "Microsoft C" gekauft, das beide enthielt Stücke (mit einem "Compiler-Treiber", der Operationen zwischen den beiden koordiniert). Obwohl der Compiler zweiteilig aufgebaut war, war es für einen normalen Entwickler, der den Compiler verwendete, nur eine einzige Sache, die vom Quellcode in den Objektcode übersetzt wurde, wobei dazwischen nichts sichtbar war.

Java verteilte stattdessen das Front-End im Java Development Kit und das Back-End in der Java Virtual Machine. Jeder Java-Benutzer hatte ein Compiler-Back-End, um auf das von ihm verwendete System zuzugreifen. Java-Entwickler verteilten Code im Zwischenformat, sodass die JVM beim Laden alles Notwendige tat, um ihn auf ihrem jeweiligen Computer auszuführen.

Präzedenzfälle

Beachten Sie, dass dieses Verteilungsmodell auch nicht ganz neu war. Nur zum Beispiel funktionierte das UCSD-P-System ähnlich: Compiler-Frontends erzeugten P-Code, und jede Kopie des P-Systems enthielt eine virtuelle Maschine, die das tat, was notwendig war, um den P-Code auf diesem bestimmten Ziel 1 auszuführen .

Java-Bytecode

Java byte code ist hinreichend ähnlich zu P-code. Grundsätzlich handelt es sich um Anweisungen für eine relativ einfache Maschine. Diese Maschine soll eine Abstraktion bestehender Maschinen sein, so dass es ziemlich einfach ist, sie schnell auf fast jedes spezifische Ziel zu übersetzen. Die einfache Übersetzung war von Anfang an wichtig, da die ursprüngliche Absicht darin bestand, Bytecodes zu interpretieren, ähnlich wie es P-System getan hatte (und ja, genau so funktionierten die frühen Implementierungen).

Stärken

Java-Bytecode ist für ein Compiler-Front-End einfach zu erstellen. Wenn Sie (zum Beispiel) einen ziemlich typischen Baum haben, der einen Ausdruck darstellt, ist es normalerweise ziemlich einfach, den Baum zu durchlaufen und Code ziemlich direkt von dem zu generieren, was Sie an jedem Knoten finden.

Java-Bytecodes sind recht kompakt - in den meisten Fällen viel kompakter als der Quellcode oder der Maschinencode für die meisten typischen Prozessoren (und insbesondere für die meisten RISC-Prozessoren, wie den SPARC, den Sun bei der Entwicklung von Java verkauft hat). Dies war zu dieser Zeit besonders wichtig, da Java vor allem Applets unterstützen wollte - Code, der in Webseiten eingebettet war, die vor der Ausführung heruntergeladen wurden - zu einer Zeit, als die meisten Leute um ca. 28.8 Uhr über Modems über Telefonleitungen auf das we zugegriffen haben Kilobit pro Sekunde (obwohl es natürlich immer noch einige Leute gab, die ältere, langsamere Modems verwendeten).

Schwächen

Die größte Schwäche von Java-Bytecodes besteht darin, dass sie nicht besonders aussagekräftig sind. Obwohl sie die in Java vorhandenen Konzepte ziemlich gut ausdrücken können, funktionieren sie nicht annähernd so gut, um Konzepte auszudrücken, die nicht Teil von Java sind. Während es auf den meisten Computern einfach ist, Byte-Codes auszuführen, ist dies auf eine Weise, die die Vorteile eines bestimmten Computers voll ausnutzt, viel schwieriger.

Wenn Sie beispielsweise Java-Bytecodes wirklich optimieren möchten, müssen Sie im Grunde ein Reverse Engineering durchführen, um sie von einer maschinencodeähnlichen Darstellung rückwärts zu übersetzen und sie wieder in SSA-Anweisungen (oder etwas Ähnliches) umzuwandeln . Sie manipulieren dann die SSA-Anweisungen, um Ihre Optimierung durchzuführen, und übersetzen von dort in etwas, das auf die Architektur abzielt, die Ihnen wirklich am Herzen liegt. Selbst bei diesem ziemlich komplexen Prozess sind einige Java-fremde Konzepte so schwierig auszudrücken, dass es schwierig ist, aus einigen Quellensprachen in Maschinencode zu übersetzen, der auf den meisten typischen Maschinen (sogar nahezu) optimal ausgeführt wird.

Zusammenfassung

Wenn Sie nach dem Grund für die Verwendung von Zwischendarstellungen im Allgemeinen fragen, sind zwei Hauptfaktoren:

  1. Reduzieren Sie ein O (N * M) -Problem auf ein O (N + M) -Problem, und
  2. Teilen Sie das Problem in handlichere Teile auf.

Wenn Sie nach den Besonderheiten der Java-Bytecodes fragen und wissen, warum diese bestimmte Darstellung anstelle einer anderen gewählt wurde, würde ich sagen, dass die Antwort weitgehend auf ihre ursprüngliche Absicht und die damaligen Einschränkungen des Webs zurückgeht , was zu folgenden Prioritäten führt:

  1. Kompakte Darstellung.
  2. Einfach und schnell zu dekodieren und auszuführen.
  3. Schnell und einfach auf den meisten gängigen Maschinen zu implementieren.

In der Lage zu sein, viele Sprachen zu repräsentieren oder eine Vielzahl von Zielen optimal zu erfüllen, waren viel niedrigere Prioritäten (wenn sie überhaupt als Prioritäten angesehen wurden).


  1. Warum wird das P-System so oft vergessen? Meist eine Preissituation. Das P-System verkaufte sich recht gut für Apple II, Commodore SuperPets usw. Als der IBM-PC herauskam, war das P-System ein unterstütztes Betriebssystem, aber MS-DOS kostete weniger (aus der Sicht der meisten Leute war es im Wesentlichen kostenlos) und Hatte schnell mehr Programme zur Verfügung, da es das ist, wofür Microsoft und IBM (unter anderem) geschrieben haben.
  2. So funktioniert beispielsweise Ruß .
Jerry Sarg
quelle
Ganz in der Nähe der Web-Applets: Die ursprüngliche Absicht bestand darin, Code auf Appliances (Set-Top-Boxen ...) zu verteilen, genauso wie RPC Funktionsaufrufe und CORBA Objekte verteilt.
Ninjalj
2
Dies ist eine großartige Antwort und ein guter Einblick, wie unterschiedliche Zwischendarstellungen unterschiedliche Kompromisse eingehen. :)
IMSoP
@ninjalj: Das war wirklich Oak. Zu dem Zeitpunkt, als es sich in Java verwandelt hatte, waren meiner Meinung nach die Ideen für Set-Top-Boxen (und ähnliche) zurückgestellt worden (obwohl ich als erster zugeben muss, dass es ein faires Argument dafür gibt, dass Oak und Java dasselbe sind).
Jerry Coffin
@TobySpeight: Ja, da passt der Ausdruck wahrscheinlich besser. Vielen Dank.
Jerry Coffin
0

Zusätzlich zu den Vorteilen, auf die andere hingewiesen haben, ist Bytecode viel kleiner, sodass die Verteilung und Aktualisierung einfacher ist und weniger Platz in der Zielumgebung beansprucht. Dies ist besonders wichtig in Umgebungen mit beengten Platzverhältnissen.

Es erleichtert auch den Schutz von urheberrechtlich geschütztem Quellcode.

EJoshuaS - Setzen Sie Monica wieder ein
quelle
2
Java- (und .NET-) Bytecode lässt sich so einfach in eine einigermaßen lesbare Quelle zurückverwandeln, dass es Produkte gibt, mit denen Namen und manchmal andere Informationen verfälscht werden können, um dies zu erschweren. Dies wird auch häufig mit JavaScript durchgeführt, um es zu verkleinern, da wir gerade erst sind Möglicherweise wird ein Bytecode für Webbrowser festgelegt.
LnxPrgr3
0

Der Sinn ist, dass das Kompilieren von Bytecode zu Maschinencode schneller ist, als das just-in-time-Interpretieren Ihres ursprünglichen Codes zu Maschinencode. Wir benötigen jedoch Interpretationen, um unsere Anwendung plattformübergreifend zu gestalten, da wir unseren Originalcode auf jeder Plattform ohne Änderungen und ohne Vorbereitungen (Kompilierungen) verwenden möchten. Also kompiliert Javac zuerst unseren Quellcode in Byte-Code, dann können wir diesen Byte-Code überall ausführen und er wird von Java Virtual Machine so interpretiert, dass er Code schneller verarbeitet. Die Antwort: Es spart Zeit.

Sergey Orlov
quelle
0

Ursprünglich war die JVM ein reiner Dolmetscher . Und Sie erhalten den Dolmetscher mit der besten Leistung, wenn die von Ihnen gedolmetschte Sprache so einfach wie möglich ist. Das war das Ziel des Bytecodes: Eine effizient interpretierbare Eingabe für die Laufzeitumgebung. Diese einzige Entscheidung brachte Java näher an eine kompilierte Sprache als an eine interpretierte Sprache, gemessen an ihrer Leistung.

Erst später, als sich herausstellte, dass die Leistung der interpretierenden JVMs immer noch nicht zufriedenstellend war, wurde der Aufwand betrieben, um leistungsfähige Just-in-Time-Compiler zu erstellen. Dies schloss die Lücke zu schnelleren Sprachen wie C und C ++. (Einige Java-inhärente Geschwindigkeitsprobleme bleiben jedoch bestehen, sodass Sie wahrscheinlich niemals eine Java-Umgebung erhalten, die so gut funktioniert wie gut geschriebener C-Code.)

Natürlich können wir mit den verfügbaren Kompilierungstechniken für Just-in-Time-Code wieder auf die eigentliche Verteilung des Quellcodes und die Just-in-Time-Kompilierung in Maschinencode zurückgreifen. Dies würde jedoch die Startleistung stark verringern, bis alle relevanten Teile des Codes kompiliert sind. Der Bytecode ist hier immer noch eine wichtige Hilfe, da er viel einfacher zu analysieren ist als der entsprechende Java-Code.

cmaster
quelle
Würde es dem Downvoter etwas ausmachen zu erklären, warum ?
cmaster
-5

Text Source Code ist eine Struktur, die für den Menschen leicht lesbar und veränderbar sein soll .

Bytecode ist eine Struktur, die leicht von einer Maschine gelesen und ausgeführt werden soll.

Da alles, was die JVM mit Code macht, gelesen und ausgeführt wird, ist Byte-Code für die JVM besser geeignet.

Mir ist aufgefallen, dass es noch keine Beispiele gegeben hat. Dumme Pseudobeispiele:

//Source code
i += 1 + 5 * 2 + x;

// Byte code
i += 11, i += x
____

//Source code
i = sin(1);

// Byte code
i = 0.8414709848
_____

//Source code
i = sin(x)^2+cos(x)^2;

// Byte code (actually that one isn't true)
i = 1

Natürlich geht es bei Bytecode nicht nur um Optimierungen. Ein großer Teil davon besteht darin, Code ausführen zu können, ohne sich um komplizierte Regeln kümmern zu müssen, z. B. zu prüfen, ob die Klasse irgendwo weiter unten in der Datei einen Member namens "foo" enthält, wenn eine Methode auf "foo" verweist.

Peter
quelle
2
Diese Bytecode- "Beispiele" sind für den Menschen lesbar. Das ist überhaupt kein Bytecode. Dies ist irreführend und geht auch nicht auf die gestellte Frage ein.
Wildcard
@Wildcard Möglicherweise haben Sie verpasst, dass dies ein von Menschen gelesenes Forum ist. Deshalb habe ich Inhalte in eine für Menschen lesbare Form gebracht. Angesichts der Tatsache, dass es sich im Forum um Software-Engineering handelt, ist es nicht besonders wichtig, die Leser zu bitten, das Konzept der einfachen Abstraktion zu verstehen.
Peter
Vom Menschen lesbare Form ist Quellcode, nicht Byte-Code. Sie veranschaulichen Quellcode mit vorberechneten Ausdrücken, NICHT mit Byte-Code. Und ich habe nicht übersehen, dass dies ein für Menschen lesbares Forum ist: Sie haben die anderen Antwortenden dafür kritisiert, dass sie keine Beispiele für Bytecode angegeben haben, nicht ich. Sie sagen also "Ich habe bemerkt, dass es noch keine Beispiele gibt" und fahren dann mit Nicht- Beispielen fort, die den Bytecode überhaupt nicht veranschaulichen. Und das spricht die Frage noch gar nicht an. Lesen Sie die Frage noch einmal.
Wildcard