Einführung in die VM-Architektur


[ Seminar "Java und Werkzeuge für das Web" ] ... [ Inhaltsverzeichnis ] ... [ zurück ] ... [ weiter ] ... [ Literaturverzeichnis ]

Übersicht: Einführung in die VM-Architektur


Aufgabe der Java-VM

Die Sprache Java wurde unter anderem mit dem Ziel entwickelt, größtmögliche Plattformunabhängigkeit zu gewährleisten. Aus diesem Grunde wurde eine speziell auf diese Programmiersprache zugeschnittene "Maschinensprache" entwickelt, der so genannte Bytecode. Dieser wurde nicht so gestaltet, dass er einer real existierenden Hardwarearchitektur entspricht, sondern anhand einer abstrakten Maschinenspezifikation, der so genannten Virtuellen Maschine (Virtual Machine, VM).
Der Vorteil dieser Vorgehensweise ist, dass man, um beliebige Java-Programme auf eine andere Plattform zu portieren, nur eine (Software-) Implementation dieser VM benötigt, welche auf der Zielplattform läuft. Bei der Spezifikation dieser Maschine wurde die konkrete Implementation größtenteils freigestellt, so dass Programmierer sie für das jeweilige Zielsystem optimal entwickeln können. Die Spezifikation legt in großen Teilen nur fest, wie die Maschine Programme nach außen hin abzuarbeiten hat, und nicht, wie der Aufbau im Inneren aussehen muss. Die Aufgaben, die eine VM zu erfüllen hat, lassen sich wie folgt gliedern: Für beide Schritte sind unterschiedliche Komponenten der VM zuständig, die im folgenden näher betrachtet werden.

Der Class-Loader

Aufgabe der Classloader (CL) ist es, Java-Klassen in den Speicher zu laden und für die Ausführung vorzubereiten. Es ist Virtuellen Machinen gestattet, auch andere Formate als das Java-Klassen-Format zu lesen und zu verarbeiten, jedoch müssen sie mindestens dieses Format erkennen.
Grundsätzlich sind Classloader ihrerseits ebenfalls Klassen, und zwar Nachkommen von java.lang.Classloader. Um aber überhaupt eine Klasse in den Speicher laden zu können, benötigt man mindestens einen Classloader, der seinerseits keine Java-Klasse ist. Diese Aufgabe erfüllt der so genannte Bootstrap-Classloader, der ein fester Bestandteil der VM ist. Seine Aufgabe ist es, die Kern-Klassen der Java-API (Klassen aus dem Package java.lang) zu laden - und somit auch weitere Classloader-Klassen. Der Bootstrap-Classloader hat immer nur eine einzige Möglichkeit, Klassen zu laden. Diese Möglichkeit hängt von der Hardware-Umgebung der VM ab, wird aber meistens darin bestehen, class-Dateien von einem lokalen Datenträger zu lesen.
Benutzerdefinierte Classloader, also Nachkommen von java.lang.Classloader, sind da flexibler, und können beispielsweise Möglichkeiten implementieren, Klassen über ein Netzwerk oder aus einer Datenbank zu laden, oder auch Bytecode 'on the fly' zu erzeugen. Ein Beispiel für einen Fall, in dem Klassen über ein Netzwerk gelesen müssen, sind Java-Applets.
Jedes Java-Programm enthält mindestens einen 'benutzerdefinierten' Classloader, der die selbstgeschriebenen (Nicht-API) Klassen lädt. Dieser (auch "System-Classloader" genannt) wird allerdings, trotz der Bezeichnung, von der VM selbst erzeugt.

Die Execution-Engine

Wurde eine Klasse von einem Classloader in den Speicher geladen, kann der in ihr enthaltene Bytecode ausgeführt werden. Dies ist Aufgabe der Execution Engine (EE).
Jeder Benutzer-Thread eines Java-Programms entspricht einer Instanz der EE. Dem Designer der VM steht es frei, auch Systemthreads (z.B. Garbage-Collection) als EE-Instanzen laufen zu lassen, aber dies ist von der VM-Spezifikation nicht zwingend vorgeschrieben.
Die EE führt schrittweise den Bytecode, den die Klasse enthält, aus. Stößt sie auf einen Aufruf einer nativen Methode, also den Aufruf einer Betriebssystemfunktion, dann delegiert sie die Ausführung des Threads an die entsprechende dynamisch gebundene Bibliothek, die diese Funktion enthält. Wie die Codeausführung intern auszusehen hat, lässt die Spezifikation offen. So kann der Bytecode Schritt für Schritt interpretiert werden, oder auch direkt vor Aufruf in den Maschinencode der Hardware-Plattform compiliert werden (Just-in-time - Compilierung). Mehr Details hierzu finden sich im nächsten Seminarthema.
Gibt es mehrere Benutzer-Threads, so schreibt die Spezifikation vor, dass der Thread mit der höchsten Priorität zu jedem Zeitpunkt etwas CPU-Zeit bekommen muss. Ob Threads mit niedrigerer Priorität auch laufen oder komplett gestoppt werden, hängt von der jeweiligen Implementation der VM ab und ist nicht definiert.

Das Native Method Interface

Die VM muss außerdem nativen Methoden, die die Schnittstelle zum Betriebssystem bilden, eine Möglichkeit geben, auf den Speicher des Java-Programms zuzugreifen. Diese Aufgabe erfüllt das Native Method Interface, also die Schnittstelle für native Methoden. Wie diese Schnittstelle auszusehen hat, ist nicht spezifiziert und hängt natürlich von den jeweils verwendeten Bibliotheken ab, die diese nativen Methoden beinhalten.
Es existiert eine Spezifikation von Sun, das JNI (Java Native Interface). Diese ist jedoch kein Muss, sondern ein Vorschlag, der darauf abzielt, einen Standard zu schaffen, durch den verschiedene VMs, die auf der gleichen Hardware-Plattform laufen, die gleichen nativen Bibliotheken verwenden können. Prinzipiell kann jeder VM-Programmierer seine eigene Schnittstelle spezifizieren.
[ Seminar "Java und Werkzeuge für das Web" ] ... [ Inhaltsverzeichnis ] ... [ zurück ] ... [ oben ] ... [ weiter ] ... [ Literatur ]