Unterschiede zwischen MSIL und Java Bytecode?

Antworten:

75

Lassen Sie mich zunächst sagen, dass ich nicht denke, dass die subtilen Unterschiede zwischen Java-Bytecode und MSIL einen unerfahrenen .NET-Entwickler stören sollten. Beide dienen dem gleichen Zweck, eine abstrakte Zielmaschine zu definieren, die eine Schicht über der am Ende verwendeten physischen Maschine ist.

MSIL und Java-Bytecode sind sehr ähnlich. Tatsächlich gibt es ein Tool namens Grasshopper, das MSIL in Java-Bytecode übersetzt. Ich war Teil des Entwicklungsteams für Grasshopper, damit ich ein wenig von meinem (verblassten) Wissen teilen kann. Bitte beachten Sie, dass ich mit der Veröffentlichung von .NET Framework 2.0 aufgehört habe, daran zu arbeiten, sodass einige dieser Dinge möglicherweise nicht mehr zutreffen (wenn ja, hinterlassen Sie bitte einen Kommentar und ich werde ihn korrigieren).

  • .NET ermöglicht benutzerdefinierte Typen mit Wertesemantik, die der regulären Referenzsemantik ( struct) zugeordnet sind.
  • .NET unterstützt vorzeichenlose Typen, wodurch der Befehlssatz etwas umfangreicher wird.
  • Java enthält die Ausnahmespezifikation von Methoden im Bytecode. Obwohl die Ausnahmespezifikation normalerweise nur vom Compiler erzwungen wird, kann sie von der JVM erzwungen werden, wenn ein anderer als der Standardklassenlader verwendet wird.
  • .NET-Generika werden in IL ausgedrückt, während Java-Generika nur die Typlöschung verwenden .
  • .NET-Attribute haben in Java keine Entsprechung (stimmt das noch?).
  • .NET enumssind nicht viel mehr als Wrapper für ganzzahlige Typen, während Javaenums ziemlich vollwertige Klassen sind (danke an Internet Friend für das Kommentieren).
  • .NET hat outund refParameter.

Es gibt andere Sprachunterschiede, aber die meisten werden nicht auf Bytecode-Ebene ausgedrückt. Wenn beispielsweise der Speicher für Javas nicht- staticinnere Klassen (die in .NET nicht vorhanden sind) keine Bytecode-Funktion darstellt, generiert der Compiler ein zusätzliches Argument für der Konstruktor der inneren Klasse und übergibt das äußere Objekt. Gleiches gilt für .NET-Lambda-Ausdrücke.

Motti
quelle
In Bezug auf Attribute - Java-Annotationen können so eingestellt werden, dass sie auch im Bytecode erscheinen, sodass es eine Entsprechung gibt.
Eiche
@Oak: Java-Annotationen erlauben nur das Übergeben von Daten, während .NET-Attribute voll leistungsfähige Klassen sind, die möglicherweise über Logik verfügen und vor allem Schnittstellen implementieren.
Fyodor Soikin
Bytecode hat auch separate Rückgabeanweisungen für jede Art von Rückgabetyp, keine Ahnung, ob dies tatsächlich zur Typensicherheit beiträgt.
Cecil Geschirrspüler
1
Die Tatsache, dass Werttypen in .NET manchmal auf dem Stapel zugewiesen werden können, ist im Vergleich zu der Tatsache, dass sie eine Wertsemantik aufweisen , von trivialer Bedeutung . Jeder Wertspeicherort ist eine Instanz. Im Gegensatz dazu ist jeder Speicherort in Java entweder eine primitive oder eine promiskuitive Objektreferenz. Es gibt keine anderen Typen.
Supercat
1
Haben Sie sich gefragt, wie sie die Leistung vergleichen? Ist MSIL schneller zu interpretieren als Bytecode für z.
Luke T O'Brien
23

CIL (der richtige Name für MSIL) und Java-Bytecode sind mehr gleich als verschieden. Es gibt jedoch einige wichtige Unterschiede:

1) CIL wurde von Anfang an als Ziel für mehrere Sprachen entwickelt. Als solches unterstützt es ein viel umfangreicheres Typsystem, einschließlich vorzeichenbehafteter und vorzeichenloser Typen, Werttypen, Zeiger, Eigenschaften, Delegaten, Ereignisse, Generika, eines Objektsystems mit einer einzigen Wurzel und mehr. CIL unterstützt Funktionen, die für die anfänglichen CLR-Sprachen (C # und VB.NET) nicht erforderlich sind, wie globale Funktionen und Tail-Call-Optimierungen . Im Vergleich dazu wurde Java-Bytecode als Ziel für die Java-Sprache entwickelt und spiegelt viele der in Java selbst festgestellten Einschränkungen wider. Es wäre viel schwieriger, C oder Schema mit Java-Bytecode zu schreiben.

2) CIL wurde so konzipiert, dass es sich problemlos in native Bibliotheken und nicht verwalteten Code integrieren lässt

3) Java-Bytecode wurde so konzipiert, dass er entweder interpretiert oder kompiliert werden kann, während CIL nur unter der Annahme einer JIT-Kompilierung entworfen wurde. Bei der ersten Implementierung von Mono wurde jedoch ein Interpreter anstelle einer JIT verwendet.

4) CIL wurde so konzipiert ( und spezifiziert ), dass es ein von Menschen lesbares und beschreibbares Assembler-Formular enthält, das direkt dem Bytecode-Formular zugeordnet ist. Ich glaube, dass Java-Bytecode (wie der Name schon sagt) nur maschinenlesbar sein sollte. Natürlich lässt sich Java-Bytecode relativ leicht wieder in das ursprüngliche Java zurückkompilieren und kann, wie unten gezeigt, auch "zerlegt" werden.

Ich sollte beachten, dass die JVM (die meisten von ihnen) stärker optimiert ist als die CLR (eine von ihnen). Die Rohleistung könnte daher ein Grund sein, lieber auf Java-Bytecode abzuzielen. Dies ist jedoch ein Implementierungsdetail.

Einige Leute sagen, dass der Java-Bytecode für mehrere Plattformen ausgelegt war, während CIL nur für Windows ausgelegt war. Das ist nicht der Fall. Es gibt einige "Windows" -Ismen im .NET-Framework, aber keine in CIL.

Als Beispiel für Punkt 4) oben habe ich vor einiger Zeit ein Spielzeug-Java an den CIL-Compiler geschrieben. Wenn Sie diesem Compiler das folgende Java-Programm geben:

class Factorial{
    public static void main(String[] a){
    System.out.println(new Fac().ComputeFac(10));
    }
}

class Fac {
    public int ComputeFac(int num){
    int num_aux ;
    if (num < 1)
        num_aux = 1 ;
    else 
        num_aux = num * (this.ComputeFac(num-1)) ;
    return num_aux ;
    }
}

Mein Compiler wird die folgende CIL ausspucken:

.assembly extern mscorlib { }
.assembly 'Factorial' { .ver  0:0:0:0 }
.class private auto ansi beforefieldinit Factorial extends [mscorlib]System.Object
{
   .method public static default void main (string[] a) cil managed
   {
      .entrypoint
      .maxstack 16
      newobj instance void class Fac::'.ctor'()
      ldc.i4 3
      callvirt instance int32 class Fac::ComputeFac (int32)
      call void class [mscorlib]System.Console::WriteLine(int32)
      ret
   }
}

.class private Fac extends [mscorlib]System.Object
{
   .method public instance default void '.ctor' () cil managed
   {
      ldarg.0
      call instance void object::'.ctor'()
      ret
   }

   .method public int32 ComputeFac(int32 num) cil managed
   {
      .locals init ( int32 num_aux )
      ldarg num
      ldc.i4 1
      clt
      brfalse L1
      ldc.i4 1
      stloc num_aux
      br L2
   L1:
      ldarg num
      ldarg.0
      ldarg num
      ldc.i4 1
      sub
      callvirt instance int32 class Fac::ComputeFac (int32)
      mul
      stloc num_aux
   L2:
      ldloc num_aux
      ret
   }
}

Dies ist ein gültiges CIL-Programm, das in einen CIL-Assembler eingespeist werden kann ilasm.exe, um eine ausführbare Datei zu erstellen. Wie Sie sehen können, ist CIL eine vollständig von Menschen lesbare und beschreibbare Sprache. Sie können problemlos gültige CIL-Programme in jedem Texteditor erstellen.

Sie können das obige Java-Programm auch mit dem javacCompiler kompilieren und dann die resultierenden Klassendateien über den javap"Disassembler" ausführen , um Folgendes zu erhalten:

class Factorial extends java.lang.Object{
Factorial();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   new #3; //class Fac
   6:   dup
   7:   invokespecial   #4; //Method Fac."<init>":()V
   10:  bipush  10
   12:  invokevirtual   #5; //Method Fac.ComputeFac:(I)I
   15:  invokevirtual   #6; //Method java/io/PrintStream.println:(I)V
   18:  return

}

class Fac extends java.lang.Object{
Fac();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public int ComputeFac(int);
  Code:
   0:   iload_1
   1:   iconst_1
   2:   if_icmpge   10
   5:   iconst_1
   6:   istore_2
   7:   goto    20
   10:  iload_1
   11:  aload_0
   12:  iload_1
   13:  iconst_1
   14:  isub
   15:  invokevirtual   #2; //Method ComputeFac:(I)I
   18:  imul
   19:  istore_2
   20:  iload_2
   21:  ireturn
}

Die javapAusgabe ist (meines Wissens) nicht kompilierbar, aber wenn Sie sie mit der obigen CIL-Ausgabe vergleichen, können Sie sehen, dass die beiden sehr ähnlich sind.

Justin
quelle
2
Es stellte sich heraus, dass versucht wurde, eine lesbare / beschreibbare Java-Assemblersprache zu erstellen. Zwei, die ich gefunden habe, sind Jasmin und Java Bytecode Assembler
Justin
2
Ich habe hier eine geschrieben, die viel besser ist. Im Gegensatz zu Jasmin ist es so konzipiert, dass es alle gültigen Klassendateien zerlegen und wieder zusammensetzen kann. github.com/Storyyeller/Krakatau . Ich denke, es wäre genauer zu sagen, dass Microsoft einen Standard-Assembler bereitstellt, während Java-Codierer ihre eigenen erstellen müssen.
Antimon
22

Sie machen im Wesentlichen dasselbe, MSIL ist Microsofts Version des Java-Bytecodes.

Die Hauptunterschiede intern sind:

  1. Bytecode wurde sowohl für die Kompilierung als auch für die Interpretation entwickelt, während MSIL explizit für die JIT-Kompilierung entwickelt wurde
  2. MSIL wurde entwickelt, um mehrere Sprachen (C # und VB.NET usw.) zu unterstützen, während Bytecode nur für Java geschrieben wird, was dazu führt, dass Bytecode Java syntaktisch ähnlicher ist als IL einer bestimmten .NET-Sprache
  3. MSIL hat eine explizitere Abgrenzung zwischen Wert- und Referenztypen

Viele weitere Informationen und einen detaillierten Vergleich finden Sie in diesem Artikel von K John Gough (Postscript-Dokument)

Guy Starbuck
quelle
"1.Bytecode wurde sowohl für die Kompilierung als auch für die Interpretation entwickelt, während MSIL explizit für die JIT-Kompilierung entwickelt wurde." - Hier geht es darum, wie Java-Code zu Bytecode kompiliert wird UND dieser Bytecode interpretiert wird. Hab ich recht? Wird MSIL nicht zur Ausführung interpretiert?
Abdul
2

CIL aka MSIL soll für Menschen lesbar sein. Java-Bytecode ist nicht.

Stellen Sie sich Java-Bytecode als Maschinencode für Hardware vor, die nicht vorhanden ist (aber von JVMs emuliert wird).

CIL ist eher eine Assemblersprache - ein Schritt vom Maschinencode entfernt und dennoch für den Menschen lesbar.

schlank
quelle
Bytecode ist eigentlich sehr gut lesbar, solange Sie einen Hex-Editor haben. Es ist eine ziemlich einfache stapelbasierte Sprache mit Erweiterungen zur direkten Darstellung von Klassen und Methoden. Ich dachte, dass MSIL niedriger ist (zB Register)?
Daniel Spiewak
en.wikibooks.org/wiki/… en.wikibooks.org/wiki/… Eines ist das rohe CIL. Der andere ist zerlegter Bytecode. Bytecode ist möglicherweise einigermaßen lesbar, wenn Sie hexadezimal bearbeiten, aber das ist kein Entwurfsziel.
schlank
"Zerlegt" ist wirklich das falsche Wort dafür. Vielleicht "entschlüsselt". Bytecode ist in den .class-Dateien nur aus Gründen der Kompaktheit nicht lesbar. Im Gegensatz zur Manpage von javap ist es nicht erforderlich, lesbaren Bytecode aus einer kompilierten Klasse zu erstellen.
Daniel Spiewak
2

Es gibt nicht so viele Unterschiede. Beide sind Zwischenformate des von Ihnen geschriebenen Codes. Bei der Ausführung führen die virtuellen Maschinen die verwaltete Zwischensprache aus. Dies bedeutet, dass die virtuelle Maschine die Variablen und Aufrufe steuert. Es gibt sogar eine Sprache, an die ich mich momentan nicht erinnere und die auf dieselbe Weise bei .Net und Java ausgeführt werden kann.

Im Grunde ist es nur ein anderes Format für das gleiche

Bearbeiten: Gefunden die Sprache (neben Scala): Es ist FAN ( http://www.fandev.org/ ), sieht sehr interessant aus, aber noch keine Zeit zu bewerten

GHad
quelle
Scala kann so kompiliert werden, dass es auf die JVM oder die CLR abzielt und Bytecode bzw. MSIL generiert.
Daniel Spiewak
Gut zu wissen, aber ich habe vor ungefähr einem Monat eine andere Sprache gefunden, als ich DZone gelesen habe: Gefunden! Siehe Bearbeiten meines Beitrags
GHad
1

Einverstanden sind die Unterschiede klein genug, um als Anfänger zu arbeiten. Wenn Sie .Net ausgehend von den Grundlagen lernen möchten, empfehlen wir Ihnen, sich die Common Language Infrastructure und das Common Type System anzusehen.

Internet-Freund
quelle
1

Ich denke, MSIL sollte nicht mit Java-Bytecode verglichen werden, sondern mit "der Anweisung, die die Java-Bytecodes enthält".

Es gibt keinen Namen für den zerlegten Java-Bytecode. "Java Bytecode" sollte ein inoffizieller Alias ​​sein, da ich seinen Namen nicht im offiziellen Dokument finden kann. Der Java Class File Disassembler sagt

Druckt disassemblierten Code, dh die Anweisungen, die die Java-Bytecodes enthalten, für jede der Methoden in der Klasse aus. Diese sind in der Java Virtual Machine-Spezifikation dokumentiert.

Sowohl "Java VM-Anweisungen" als auch "MSIL" werden zu .NET-Bytecode und Java-Code zusammengesetzt, die nicht von Menschen gelesen werden können.

Dennis C.
quelle