2008-09-07 11 views
38

Es scheint, als ob alles, was Sie mit Bytecode tun können, genauso einfach und viel schneller in nativem Code möglich ist. Theoretisch könnten Sie sogar die Unabhängigkeit von Plattform und Sprache beibehalten, indem Sie Programme und Bibliotheken in Bytecode verteilen und dann bei der Installation in nativen Code kompilieren, anstatt ihn zu JITEN.Was sind die Vorteile von Bytecode gegenüber nativem Code?

Also, im Allgemeinen, wann möchten Sie Bytecode anstelle von nativen ausführen?

Antwort

31

Hank Shiffman von SGI sagte (vor langer Zeit, aber es ist bis wahr):

Es gibt drei Vorteile von Java mit dem Byte-Code anstelle des Gehens den nativen Code des Systems :

  1. Portabilität: Jede Art von Computer hat seine einzigartige Anweisung Satz. Während einige Prozessoren die Anweisungen für ihre Vorgänger, enthalten, ist es allgemein wahr, dass ein Programm , das auf einer Art von Computer ausgeführt wird, auf keinem anderen ausgeführt wird. Fügen Sie die Dienste hinzu, die von dem Betriebssystem bereitgestellt werden, das jedes System in seine eigene einzigartige Weise beschreibt, und Sie haben ein Kompatibilitätsproblem. In der Regel können Sie nicht schreiben und kompilieren ein Programm für eine Art von System und führen Sie es auf jedem anderen ohne viel Arbeit.Java bekommt um diese Einschränkung durch Einfügen seiner virtuellen Maschine zwischen der Anwendung und der realen Umgebung (Computer + Betriebssystem). Wenn eine Anwendung auf Java Byte Code kompiliert und dass Byte-Code wird dann in jeder Umgebung die gleiche Art und Weise interpretiert Sie ein einzelnes Programm schreiben können, die werden die verschiedenen Plattformen auf alle arbeiten, wo Java unterstützt wird. (Das ist die Theorie, sowieso In Praxis gibt es immer wieder kleine auf der Lauer Inkompatibilitäten für die Programmierer..)

  2. Sicherheit: Einer der Vorzüge von Java ist die Integration in das Web. Laden Sie eine Webseite, die Java in Ihrem Browser verwendet und der Java-Code automatisch heruntergeladen und ausgeführt wird. Aber was ist, wenn der Code Dateien zerstört, ob durch Bosheit oder Schlamperei auf Seiten des Programmierers? Java verhindert, dass heruntergeladene Applets irgendetwas Zerstörendes tun, indem sie potentiell gefährliche Operationen verbieten. Bevor der Code ausgeführt werden kann, prüft er auf Versuche, die Sicherheit zu umgehen. Es überprüft, dass Daten konsistent konsumiert werden: Code, manipuliert ein Datenelement als eine Ganzzahl in einer Phase und versucht dann, es als Zeiger zu verwenden, wird später abgefangen und verhindert ausgeführt werden. (Die Java Sprache erlaubt keine Zeiger Arithmetik, so kann man nicht schreiben Java Code zu tun, was wir gerade beschrieben. Allerdings gibt nichts jemanden vom Schreiben destruktiven Byte Code selbst einen hexadezimalen zu verhindern, ist Editor oder sogar ein Java-Byte Code Assembler zu bauen.) Es ist in der Regel nicht möglich, ein Programm Maschinencode vor der Ausführung zu analysieren und festzustellen, ob es irgendetwas tut schlecht. Tricks wie Schreiben selbst-modifizierenden Code bedeuten, dass die bösen Operationen möglicherweise nicht einmal bis später existieren. Aber Java-Byte-Code wurde für diese Art der Validierung entwickelt: es hat nicht die Anweisungen ein bösartigen Programmierer würde verwenden, um ihren Angriff zu verstecken.

  3. Größe: In der Mikroprozessorwelt ist RISC im Allgemeinen über CISC vorzuziehen. Es ist besser, eine kleine Befehlssatz zu haben und viele schnelle Anweisungen zu verwenden, um eine Aufgabe zu haben als viele komplexe Operationen implementiert als einzelne Anweisungen. RISC-Designs erfordern weniger Gates auf dem Chip zu ihre Anweisungen implementieren, so dass für mehr Platz für Pipelines und andere Techniken, um jede Anweisung schneller zu machen. Bei einem Interpreter ist jedoch nichts davon wichtig. Wenn Sie eine einzelne Anweisung für die Switch-Anweisung mit einer Variablen Länge je nach der Anzahl der Fälle Klauseln implementieren möchten, gibt es keinen Grund, nicht zu tun so.In der Tat, stellte ein komplexer Befehl ist ein Vorteil für eine Web-basierten Sprache: es bedeutet, dass das gleiche Programm sein wird kleiner (weniger Anweisungen größeren Komplexität), , die weniger Zeit bedeuten über unsere drehzahl- zu übertragen begrenztes Netzwerk.

Also, wenn Bytecode vs nativen Berücksichtigung überlegen, welche Kompromisse Sie zwischen Portabilität, Sicherheit, Größe und Ausführungsgeschwindigkeit machen wollen. Wenn Geschwindigkeit der einzige wichtige Faktor ist, geh nativ. Wenn einer der anderen wichtiger ist, gehen Sie mit Bytecode.

Ich füge auch hinzu, dass die Pflege einer Reihe von OS und Architektur-bezogenen Compilations der gleichen Code-Basis für jede Veröffentlichung sehr mühsam werden kann. Es ist ein großer Gewinn, denselben Java-Bytecode auf mehreren Plattformen zu verwenden und "einfach zu funktionieren".

+4

4 Jahre später ... Portabilität: Compiler, die nativen Code erzeugen, können wie gc kompilieren (der offizielle [Go] (http://golang.org/) Compiler), was es so einfach macht. Sicherheit: [Native Client] (https://developers.google.com/native-client/) führt nativen Code in einer Sandbox aus, wodurch die Berechtigungen eingeschränkt werden. Größe: Selten ein Thema heutzutage, auch für mobile Geräte. –

+2

@Zippoxer Was ist mit den vier Jahren? Cross-Compilation ist ein sehr altes Konzept. Sie müssen den Code jedoch für jede Plattform separat kompilieren. Virtualisierung ist auch kein neues Konzept, aber die Virtualisierung von Code, der für die native Ausführung geschrieben wurde, ist nicht dasselbe wie der virtualisierte Code, der speziell für die Ausführung in einer Sandbox entwickelt wurde. Was die Größe anbelangt, würde ich den Java-Bytecode CISC überhaupt nicht nennen. Das gleiche gilt für CIL. – Malcolm

2

Ich denke, Sie haben gerade Ihre eigene Frage beantwortet: Plattformunabhängigkeit. Plattformunabhängiger Bytecode wird erzeugt und auf seine Zielplattform verteilt. Bei der Ausführung wird es entweder vor dem Beginn der Ausführung oder gleichzeitig (Just In Time) in den systemeigenen Code kompiliert. Die Java JVM und vermutlich die .NET Laufzeiten arbeiten nach diesem Prinzip.

9

Bytecode erzeugt eine zusätzliche Indirektionsstufe.

Die Vorteile dieser zusätzlichen Dereferenzierungsebene sind:

  • Plattformunabhängigkeit
  • kann eine beliebige Anzahl von Programmiersprachen (Syntax) erstellen und sie auf den gleichen Bytecode kompiliert unten.
  • Konnte problemlos Sprachumwandler erstellen
  • X86, X64 und IA64 müssen nicht mehr als separate Binärdateien kompiliert werden. Nur die richtige virtuelle Maschine muss installiert werden.
  • Jedes Betriebssystem muss nur eine virtuelle Maschine erstellen und es wird Unterstützung für das gleiche Programm haben.
  • Just-in-Time-Kompilierung ermöglicht es Ihnen, ein Programm nur durch Ersetzen einer einzelnen gepatchten Quelldatei zu aktualisieren. (Sehr vorteilhaft für Web-Seiten)

Einige der Nachteile:

  • Leistung
  • Leichter zu dekompilieren
1

Idealerweise hätten Sie einen tragbaren Bytecode, der Just In Time zu nativem Code kompiliert. Ich denke, der Grund, warum Bytecode-Interpreter ohne JIT existieren, liegt in erster Linie an der praktischen Tatsache, dass die Kompilierung von nativem Code die Komplexität einer virtuellen Maschine erhöht. Es braucht Zeit, um diese zusätzliche Komponente zu erstellen, zu debuggen und zu warten. Nicht jeder hat die Zeit oder die Ressourcen, um diese Verpflichtung zu erfüllen.

Ein zweiter Faktor ist die Sicherheit. Es ist viel einfacher zu verifizieren, dass ein Interpreter nicht abstürzt, als dasselbe für nativen Code zu garantieren.

Drittens ist die Leistung. Es kann oft länger dauern, Maschinencode zu generieren, als Bytecode für kleine Codeabschnitte zu interpretieren, die nur einmal ausgeführt werden.

15

Die Leistung von praktisch jedem Programm wird verbessert, wenn es kompiliert, mit Profiling ausgeführt wird und die Ergebnisse für einen zweiten Durchlauf in den Compiler zurückgespielt werden. Die Codepfade, die tatsächlich verwendet werden, werden aggressiver optimiert, die Schleifen werden auf genau den richtigen Grad abgerollt, und die heißen Befehlspfade werden angeordnet, um I $ Treffer zu maximieren.

Alle guten Sachen, aber es ist fast nie getan, weil es nervig ist, so viele Schritte zu durchlaufen, um eine Binärdatei zu erstellen.

Dies ist der Vorteil, wenn Sie den Bytecode einige Zeit ausführen, bevor Sie ihn in nativen Code kompilieren: Profilinformationen sind automatisch verfügbar. Das Ergebnis nach der Just-In-Time-Kompilierung ist hoch optimierter nativer Code für die spezifischen Daten, die das Programm verarbeitet.

Die Möglichkeit, den Bytecode auszuführen, ermöglicht auch eine aggressivere native Optimierung, als ein statischer Compiler sicher verwenden könnte. Wenn zum Beispiel angegeben wird, dass eines der Argumente für eine Funktion immer NULL ist, kann die gesamte Behandlung für dieses Argument einfach aus dem systemeigenen Code weggelassen werden. Es wird eine kurze Gültigkeitsprüfung der Argumente in dem Funktionsprolog geben, wenn dieses Argument nicht NULL ist, bricht die VM zurück zu dem Bytecode ab und startet das Profilieren erneut. Hier

3

Alle guten Antworten, aber mein Hot-Button wurde getroffen - Leistung.

Wenn der laufende Code all seine Zeit mit dem Aufrufen von Bibliotheks-/Systemroutinen - Dateioperationen, Datenbankoperationen, Senden von Windows-Nachrichten - verbringt, spielt es keine große Rolle, ob er JITted ist, weil die meiste Zeit darauf wartet für diese untergeordneten Vorgänge abzuschließen.

jedoch wenn der Code enthält Dinge, die wir in der Regel „Algorithmen“ nennen, die schnell sein müssen und nicht viel Zeit Funktionen verbringen Aufruf und wenn diese oft genug verwendet werden, ein Performance-Problem zu sein, dann ist JIT sehr wichtig.

0

Portabilität und Plattformunabhängigkeit sind wahrscheinlich die wichtigsten Vorteile von Bytecode gegenüber nativem Code.