it-swarm.com.de

Java Virtual Machine und CLR

Als eine Art Folgemaßnahme zu der Frage namens nterschiede zwischen MSIL und Java Bytecode? , was sind die (Haupt-) Unterschiede oder Ähnlichkeiten in der Art und Weise, wie Java Virtual Machine funktioniert im Vergleich zu .NET Framework Common Language Runtime (CLR) funktioniert?

Auch ist das .NET Framework CLR eine "virtuelle Maschine" oder hat sie nicht die Attribute einer virtuellen Maschine?

135
Frank V

Es gibt viele Ähnlichkeiten zwischen beiden Implementierungen (und meiner Meinung nach: Ja, beide sind "virtuelle Maschinen").

Zum einen handelt es sich um stapelbasierte VMs, bei denen es sich nicht um "Register" handelt, wie wir es von einer modernen CPU wie x86 oder PowerPC gewohnt sind. Die Auswertung aller Ausdrücke ((1 + 1)/2) wird durchgeführt, indem Operanden auf den "Stapel" geschoben werden und diese Operanden dann vom Stapel entfernt werden, wenn ein Befehl (Addieren, Dividieren usw.) diese Operanden verbrauchen muss. Jeder Befehl legt seine Ergebnisse auf den Stapel zurück.

Dies ist eine bequeme Möglichkeit, eine virtuelle Maschine zu implementieren, da so gut wie jede CPU auf der Welt über einen Stack verfügt, die Anzahl der Register jedoch häufig unterschiedlich ist (und einige Register einen speziellen Zweck erfüllen und jeder Befehl seine Operanden in unterschiedlichen Registern erwartet, usw.) ).

Wenn Sie also eine abstrakte Maschine modellieren möchten, ist ein rein stapelbasiertes Modell ein guter Weg.

Natürlich funktionieren echte Maschinen nicht so. Daher ist der JIT-Compiler für die Durchführung der "Registrierung" von Bytecode-Operationen verantwortlich und plant im Wesentlichen, dass die tatsächlichen CPU-Register nach Möglichkeit Operanden und Ergebnisse enthalten.

Ich denke, das ist eine der größten Gemeinsamkeiten zwischen der CLR und der JVM.

Was die Unterschiede betrifft ...

Ein interessanter Unterschied zwischen den beiden Implementierungen besteht darin, dass die CLR Anweisungen zum Erstellen generischer Typen und zum Anwenden parametrischer Spezialisierungen auf diese Typen enthält. Zur Laufzeit betrachtet die CLR eine Liste <int> als einen völlig anderen Typ als eine Liste <String>.

Im Hintergrund wird für alle Spezialisierungen von Referenztypen dieselbe MSIL verwendet (daher verwendet eine List <String> dieselbe Implementierung wie eine List <Object> mit unterschiedlichen Typumwandlungen an den API-Grenzen), wobei jedoch jeder Werttyp verwendet wird eine eigene, einzigartige Implementierung (List <int> generiert einen völlig anderen Code als List <double>).

In Java sind generische Typen ein reiner Compilertrick. Die JVM hat keine Ahnung, welche Klassen Typargumente haben, und sie kann zur Laufzeit keine parametrischen Spezialisierungen durchführen.

Aus praktischer Sicht bedeutet dies, dass Sie Java) - Methoden für generische Typen nicht überladen können. Sie können nicht zwei verschiedene Methoden mit demselben Namen verwenden, die sich nur darin unterscheiden, ob sie eine Liste akzeptieren < String> oder eine Liste <Datum>. Da die CLR parametrische Typen kennt, gibt es natürlich keine Probleme bei der Behandlung von Methoden, die bei generischen Typspezialisierungen überladen sind.

Im Alltag ist dies der Unterschied, den ich am meisten zwischen der CLR und der JVM bemerke.

Weitere wichtige Unterschiede sind:

  • Die CLR verfügt über Closures (implementiert als C # -Delegierte). Die JVM unterstützt Schließungen nur seit Java 8.

  • Die CLR verfügt über Coroutinen (implementiert mit dem Schlüsselwort C # 'yield'). Die JVM nicht.

  • Mit der CLR kann der Benutzercode neue Werttypen (Structs) definieren, während die JVM eine feste Sammlung von Werttypen (Byte, Short, Int, Long, Float, Double, Char, Boolean) bereitstellt. Außerdem können Benutzer nur neue Referenztypen definieren. Typen (Klassen).

  • Die CLR unterstützt das Deklarieren und Bearbeiten von Zeigern. Dies ist besonders interessant, da sowohl die JVM als auch die CLR strikte Garbage-Collector-Implementierungen zur Generationskomprimierung als Speicherverwaltungsstrategie verwenden. Unter normalen Umständen fällt es einem strengen Komprimierungs-GC sehr schwer, auf Zeiger zuzugreifen, da alle Zeiger (und Zeiger auf Zeiger) ungültig werden, wenn Sie einen Wert von einem Speicherort an einen anderen verschieben. Die CLR bietet jedoch einen "Pinning" -Mechanismus, mit dem Entwickler einen Codeblock deklarieren können, in dem die CLR bestimmte Zeiger nicht verschieben darf. Das ist sehr praktisch.

  • Die größte Codeeinheit in der JVM ist entweder ein 'Paket', wie durch das Schlüsselwort 'protected' belegt, oder eine JAR (dh Java= ARchive), wie durch die Angabe eines JAR in belegt In der CLR werden Klassen zu "Assemblys" zusammengefasst, und die CLR bietet Logik zum Überlegen und Bearbeiten von Assemblys (die in "AppDomains" geladen werden und eine Unteranwendungsebene bieten) Sandboxen zur Speicherzuweisung und Codeausführung).

  • Das CLR-Bytecode-Format (bestehend aus MSIL-Anweisungen und Metadaten) hat weniger Anweisungstypen als die JVM. In der JVM verfügt jede eindeutige Operation (zwei int-Werte hinzufügen, zwei float-Werte hinzufügen usw.) über eine eigene eindeutige Anweisung. In der CLR sind alle MSIL-Anweisungen polymorph (addieren Sie zwei Werte), und der JIT-Compiler ist dafür verantwortlich, die Typen der Operanden zu bestimmen und den entsprechenden Maschinencode zu erstellen. Ich weiß jedoch nicht, welche Strategie ich bevorzugen soll. Beide haben Kompromisse. Der HotSpot-JIT-Compiler für die JVM kann einen einfacheren Code-Generierungsmechanismus verwenden (er muss keine Operandentypen ermitteln, da diese bereits in der Anweisung codiert sind), dies bedeutet jedoch, dass ein komplexeres Bytecode-Format erforderlich ist. mit mehr Anweisungstypen.

Ich verwende Java (und bewundere die JVM) seit ungefähr zehn Jahren.

Aber meiner Meinung nach ist die CLR jetzt in fast jeder Hinsicht die überlegene Implementierung.

272
benjismith

Ihre erste Frage ist der Vergleich der JVM mit dem .NET Framework - ich nehme an, Sie wollten stattdessen mit der CLR vergleichen. Wenn ja, ich denke du könntest ein kleines Buch darüber schreiben ( EDIT: sieht so aus, als hätte Benji schon :-)

Ein wichtiger Unterschied besteht darin, dass die CLR im Gegensatz zur JVM als sprachneutrale Architektur konzipiert ist.

Ein weiterer wichtiger Unterschied ist, dass die CLR speziell für ein hohes Maß an Interoperabilität mit nativem Code entwickelt wurde. Dies bedeutet, dass die CLR die Zuverlässigkeit und Sicherheit beim Zugriff und Ändern des nativen Speichers sowie Marshalling verwalten zwischen CLR-basierten Datenstrukturen und nativen Datenstrukturen verwalten muss.

Zur Beantwortung Ihrer zweiten Frage ist der Begriff „virtuelle Maschine“ ein älterer Begriff aus der Hardware-Welt (z. B. die Virtualisierung der 360 durch IBM in den 1960er-Jahren), der eine Software-/Hardware-Emulation der zugrunde liegenden Maschine bezeichnete, um dieselbe Art von zu erreichen Sachen, die VMWare macht.

Die CLR wird oft als "Ausführungsmaschine" bezeichnet. In diesem Zusammenhang handelt es sich um eine Implementierung einer IL-Maschine auf einem x86. Dies ist auch das, was die JVM tut, obwohl Sie argumentieren können, dass es einen wichtigen Unterschied zwischen den polymorphen Bytecodes der CLR und den eingegebenen Bytecodes der JVM gibt.

Die pedantische Antwort auf Ihre zweite Frage lautet also "nein". Aber es kommt wirklich darauf an, wie Sie diese beiden Begriffe definieren.

BEARBEITEN: Ein weiterer Unterschied zwischen der JVM und der CLR besteht darin, dass die JVM (Version 6) sehr ungern zur Freigabe zugeteilt ist Speicher wieder auf das Betriebssystem, auch wenn es kann.

Angenommen, ein JVM-Prozess wird gestartet und weist zunächst 25 MB Arbeitsspeicher vom Betriebssystem zu. Der App-Code versucht dann, Zuordnungen vorzunehmen, für die zusätzliche 50 MB erforderlich sind. Die JVM weist zusätzliche 50 MB vom Betriebssystem zu. Sobald der Anwendungscode diesen Speicher nicht mehr verwendet, wird er nicht mehr ordnungsgemäß erfasst und die Größe des JVM-Heapspeichers wird verringert. Die JVM gibt den zugewiesenen Betriebssystemspeicher jedoch nur unter bestimmten sehr spezifischen Umständen frei. Andernfalls bleibt dieser Speicher für den Rest der Prozesslebensdauer reserviert.

Andererseits gibt die CLR den zugewiesenen Speicher an das Betriebssystem zurück, wenn er nicht mehr benötigt wird. Im obigen Beispiel hätte die CLR den Speicher freigegeben, sobald der Heap verringert wurde.

25
RoadWarrior

Weitere Einzelheiten zu den Unterschieden finden Sie unter aus verschiedenen akademischen und privaten Quellen. Ein gutes Beispiel ist CLR Design Choices .

Einige konkrete Beispiele sind:

  • Einige Low-Level-Operanden sind typisiert, z. B. "add two ints", wobei CLR einen polymorphen Operanden verwendet. (d. h. fadd/iadd/ladd vs nur hinzufügen)
  • Gegenwärtig führt die JVM eine aggressivere Laufzeitprofilerstellung und -optimierung durch (d. H. Hotspot). CLR führt derzeit JIT-Optimierungen durch, jedoch keine Laufzeitoptimierung (d. H. Code ersetzen, während Sie ausgeführt werden).
  • CLR integriert keine virtuellen Methoden, JVM ...
  • Unterstützung für Werttypen in der CLR, die über die "Grundelemente" hinausgehen.
11
James Schek

Die CLR und die JVM sind beide virtuelle Maschinen.

Das .NET Framework und die Java Runtime Environment sind die Bündelung der jeweiligen VMs und ihrer Bibliotheken. Ohne Bibliotheken sind die VMs ziemlich nutzlos.

9
Allain Lalonde