1 Übersicht
Es ist bekannt, dass Java die Plattform agnostische, Sicherheit und Netzwerkmobilität unterstützt. Die Java -Plattform besteht aus Java -Virtual -Maschinen und Java -Kernklassen, die eine einheitliche Programmierschnittstelle für reine Java -Programme liefert, unabhängig vom niedrigeren Betriebssystem. Genau an die java -virtuelle Maschine, die behauptet, "einmal zusammengestellt, überall laufen" zu werden, kann garantiert werden.
1.1 Java -Programmausführungsprozess
Die Ausführung von Java -Programmen hängt von der Zusammenstellungsumgebung und der laufenden Umgebung ab. Der Quellcode wird in ausführbare Maschinencode konvertiert, der durch den folgenden Vorgang abgeschlossen wird:
Der Kern der Java -Technologie ist die Java Virtual Machine, da alle Java -Programme auf der virtuellen Maschine ausgeführt werden. Der Betrieb von Java -Programmen erfordert die Zusammenarbeit von Java Virtual Machine, Java API und Java Class -Dateien. Die Java Virtual Machine -Instanz ist für die Ausführung eines Java -Programms verantwortlich. Wenn ein Java -Programm gestartet wird, wird eine Instanz der virtuellen Maschine geboren. Wenn das Programm endet, stirbt die Instanz der virtuellen Maschine.
Die plattformübergreifende Funktion von Java liegt daran, dass virtuelle Maschinen auf verschiedene Plattformen abzielen.
1.2 Java Virtual Machine
Die Hauptaufgabe einer java -virtuellen Maschine besteht darin, Klassendateien zu laden und die darin enthaltenen Bytecodes auszuführen. Wie aus der Abbildung unten ersichtlich ist, enthält die java virtuelle Maschine einen Klassenlader, der Klassendateien aus Programmen und APIs laden kann. Nur Klassen, die für die Programmausführung erforderlich sind, werden in Java -API geladen, und der Bytecode wird von der Ausführungs -Engine ausgeführt.
Wenn ein Java -Virtual -Computer von Software im Host -Betriebssystem implementiert wird, interagiert das Java -Programm mit dem Host, indem sie lokale Methoden aufruft. Java -Methoden sind in Java -Sprache geschrieben, in Bytecode zusammengestellt und in Klassendateien gespeichert. Die lokale Methode ist in C/C ++/Assemblersprache geschrieben, in prozessorbezogenen Maschinencode kompiliert, in der dynamischen Verbindungsbibliothek gespeichert, und das Format ist für jede Plattform proprietär. Die lokale Methode besteht also darin, Java -Programme mit dem zugrunde liegenden Host -Betriebssystem zu verbinden.
Da die Java Virtual Machine nicht weiß, wie eine Klassendatei erstellt wurde und ob sie manipuliert wurde, implementiert sie einen Klassendateidetektor, um sicherzustellen, dass die in der Klassendatei definierten Typen sicher verwendet werden können. Der Klassendatei -Checker sorgt für die Robustheit des Programms durch vier unabhängige Scans:
・ Sammlung der Klassendatei
・ Semantische Überprüfung der Typdaten
・ Bytecode -Überprüfung
・ Symbolreferenzüberprüfung
Bei der Ausführung von Bytecode führen die virtuellen Java-Maschinen auch andere integrierte Sicherheitsmechanismen durch. Sie sind die Eigenschaften, die Robustheit von Java -Programmen als Java -Programmiersprachen sicherzustellen, und sind auch die Eigenschaften von Java -virtuellen Maschinen:
・ Konvertierung von Typ-Safe-Referenz
・ Strukturierter Speicherzugriff
・ Automatische Müllsammlung
・ Array -Grenzüberprüfung
・ Leere Zitatprüfung
1.3 Datentyp Virtual Machine Java -Maschine
Java -virtuelle Maschinen führen Berechnungen über bestimmte Datentypen durch. Datentypen können in zwei Typen unterteilt werden: Grundtypen und Referenztypen, wie in der folgenden Abbildung gezeigt:
Aber Boolescher ist etwas Besonderes. Wenn der Compiler den Java -Quellcode in Bytecode kompiliert, wird Booleschen in INT oder Byte dargestellt. In Java Virtual Machines wird FALSE durch 0 dargestellt, und True wird durch alle Ganzzahlen ungleich Null dargestellt. Wie die Java-Sprache ist der Wertebereich des Grundtyps einer Java-virtuellen Maschine überall konsistent, egal wie die Hostplattform ist, eine lange ist immer eine signierte Ganzzahl mit 64-Bit-Komplement in einer virtuellen Maschine.
Für returnAddress wird dieser Basistyp verwendet, um die endgültige Klausel in einem Java -Programm zu implementieren. Java -Programmierer können diesen Typ nicht verwenden, sein Wert verweist auf den Opcode einer virtuellen Maschine.
2architektur
In der Spezifikation der virtuellen Maschine von Java wird das Verhalten einer Instanz einer virtuellen Maschine in Bezug auf Subsystem, Speicherbereich, Datentyp und Anweisungen beschrieben, und diese Komponenten zeigen zusammen die interne interne Architektur der virtuellen Maschine.
2.1 Class -Datei
Die Javaclass -Datei enthält alle Informationen zu einer Klasse oder Schnittstelle. Der "Basistyp" der Klassendatei lautet wie folgt:
| U1 | 1 Byte, nicht signierter Typ |
| U2 | 2 Bytes, nicht signierter Typ |
| U4 | 4 Bytes, nicht signierter Typ |
| U8 | 8 Bytes, nicht signierter Typ |
Wenn Sie mehr wissen möchten, gibt JVM SE7 von Oracle die offizielle Spezifikation an: die Spezifikation der virtuellen Maschine von Java®
Der Inhalt der Klassendatei:
ClassDile {u4 Magic; // magische Nummer: 0xCafebabe, verwendet, um festzustellen, ob es sich um eine Java -Klassendatei u2 moll_version handelt; // Minor -Versionsnummer U2 Major_version; // Hauptversionsnummer U2 CONSTANT_POOL_COUNT; // Konstante Poolgröße cp_info constant_pool [constant_pool_count-1]; // Konstante Pool U2 Access_flags; // Zugriffsflags bei den Klassen- und Schnittstellenebenen (durch | Operation erhalten) u2 this_class; // Klassenindex (auf Klassenkonstanten im konstanten Pool hinweisen) u2 Super_class; // Präsentieren Sie den Klassenindex (auf Klassenkonstanten im konstanten Pool hinweisen) u2 interfaces_count; // Interfaces Index -Zähler U2 -Schnittstellen [interfaces_count]; // Schnittstellenindex -Set U2 fields_count; // Feldzählungszähler field_info fields [fields_count]; // Feldtabelle Set U2 Methods_Count; // Methode Count Counter Method_info Methoden [methody_count]; // Methode Tabelle Set U2 Attribute_Count; // Anzahl der Attributattribute_info -Attribute [Attribute_Count]; // Attributtabelle} 2.2 Subsystem der Klassenlader
Das Klassenlader -Subsystem ist für die Suche und Ladeartinformationen verantwortlich. Tatsächlich gibt es zwei Arten von Ladern für virtuelle Java-Maschinen: Systemlader und benutzerdefinierte Lader. Ersteres ist Teil der Implementierung von Java Virtual Machine, während letzteres Teil des Java -Programms ist.
・ BootstrapClassloader: Es wird verwendet, um die Kernbibliothek von Java zu laden, die in nativem Code implementiert ist, und wird nicht von java.lang.classloader geerbt.
・ Erweiterungclassloader: Es wird zum Laden von Java -Erweiterungsbibliotheken verwendet. Die Implementierung der Java Virtual Machine bietet ein Erweiterungsbibliotheksverzeichnis. Dieser Klassenloader sucht nach Java -Klassen in diesem Verzeichnis und lädt nach.
・ Anwendungsklassenlader: Es wird Java -Klassen gemäß dem Klassenpfad der Java -Anwendung (Klassenpfad) geladen. Im Allgemeinen werden Java -Anwendungskurse damit geladen. Es kann über Classloader.getSystemClassloader () erhalten werden.
Zusätzlich zu den vom System bereitgestellten Klassenladern können Entwickler ihre eigenen Klassenlader implementieren, indem sie die Klasse java.lang.Classader erben, um einige besondere Bedürfnisse zu erfüllen.
Das Klassenlader -Subsystem umfasst mehrere andere Komponenten der java virtuellen Maschine und Klassen aus der Java.lang -Bibliothek. Die vom Classloader definierte Methode bietet eine Schnittstelle für das Programm zum Zugriff auf den Klassenladermechanismus. Darüber hinaus erstellt die virtuelle Java -Maschine für jeden geladenen Typ eine Instanz der Klasse java.lang.class -Klasse, um den Typ darzustellen. Wie bei anderen Objekten werden benutzerdefinierte Klassenlader und Klasseninstanzen im Haufenbereich im Speicher platziert, während sich die geladenen Typinformationen im Methodenbereich befinden.
Zusätzlich zum Auffinden und Importieren von Klassendateien muss das Klassenlader -Subsystem auch dafür verantwortlich sein, die Richtigkeit der importierten Klasse zu überprüfen, Speicher für Klassenvariablen zuzuweisen und zu initialisieren und symbolische Referenzen zu analysieren. Diese Aktionen müssen auch in der folgenden Reihenfolge ausgeführt werden:
・ Last (finde und laden Binärdaten vom Typ)
・ Verbindung (Ausführungsüberprüfung: Stellen Sie die Richtigkeit des importierten Typs sicher; Vorbereitung: Speicher für Klassenvariablen zuweisen und in die Standardwerte initialisieren; Parsen: symbolische Referenzen im Typ in direkte Referenzen umwandeln)
・ Initialisierung (Klassenvariablen werden auf den richtigen Anfangswert initialisiert)
2.3 Methodenbereich
In einer virtuellen Java -Maschine werden Informationen zum geladenen Typ in einem Methodenbereich im Speicher gespeichert. Wenn eine virtuelle Maschine einen bestimmten Typ lädt, wird ein Klassenlader verwendet, um die entsprechende Klassendatei zu finden, dann die Klassendatei liest und an die virtuelle Maschine überträgt. Anschließend extrahiert die virtuelle Maschine die darin enthaltenen Typinformationen und speichert diese Informationen im Methodenbereich. Methodenbereiche können auch vom Garbage Collector gesammelt werden, da die virtuelle Maschine die dynamische Erweiterung von Java-Programmen über benutzerdefinierte Klassenlader ermöglicht.
Die folgenden Informationen werden im Methodenbereich gespeichert:
・ Diese Art von voll qualifiziertem Namen (z. B. der voll qualifizierte Name Java.lang.Object)
・ Der voll qualifizierte Name dieser Art von direkter Superklasse
・ Ist dieser Typ Klassentyp oder Schnittstellentyp
・ Diese Art von Zugriffsmodifikator (eine Teilmenge von öffentlich, abstrakt, endgültig)
・ Sortierte Liste vollständig qualifizierter Namen für eine direkte Hyperinterface
・ Konstantes Pool dieser Art (eine geordnete Sammlung mit direkten Konstanten [String-, Ganzzahl- und FloatingPoint -Konstanten] und symbolische Verweise auf andere Typen, Felder und Methoden)
・ Feldinformationen (Feldname, Typ, Modifikator)
・ Methodeninformationen (Methodenname, Rückgabetyp, Anzahl der Parameter und Typ, Modifikator)
・ Alle Klasse (statischen) Variablen außer Konstanten
・ Verweise auf die Klasse der Klassenlader (wenn jeder Typ geladen wird, muss die virtuelle Maschine verfolgen, ob er vom Startklassenloader oder dem benutzerdefinierten Klassenloader geladen wird).
・ Verweis auf die Klassenklasse (für jeden geladenen Typ erstellt die virtuelle Maschine eine Instanz der Klasse java.lang.klasse entsprechend. Wenn Sie beispielsweise einen Hinweis auf das Objekt der java.lang.Integer -Klasse haben, müssen Sie nur die GetClass -Methode aufrufen, die von der Integer -Objekte repräsentiert wird, um die Klassenobjekt darzustellen, um das Java.lang -Class -Class -Objekt darzustellen.
2.4 Haufen
Alle Klasseninstanzen oder Arrays, die von Java -Programmen zur Laufzeit erstellt wurden (Arrays sind ein echtes Objekt in einer virtuellen Java -Maschine), werden auf demselben Haufen platziert. Da Java Virtual Machine Instances nur einen Haufen Speicherplatz hat, teilen sich alle Threads diesen Haufen. Es ist zu beachten, dass die java -virtuelle Maschine über eine Anweisung zur Zuordnung von Objekten im Haufen verfügt, aber keine Anweisung zum freien Speicher verfügt, da die virtuelle Maschine diese Aufgabe zur Verarbeitung an den Müllsammler überreicht. Die Spezifikation der virtuellen Maschine von Java erzwingt keine Müllsammler, sondern erfordert nur, dass virtuelle Maschinenimplementierungen "ihren eigenen Haufen" "auf irgendeine Weise" verwalten müssen. Beispielsweise kann eine Implementierung nur einen Haufen fester Größe haben. Wenn der Raum gefüllt ist, wirft er einfach eine Ausnahme aus, die das Problem der Recycling -Müllobjekte nicht berücksichtigt, sondern die Spezifikationen entspricht.
In der Spezifikation "Virtual Machine" Java gibt nicht an, wie Java -Objekte im Heap dargestellt werden, was dem Implementierer der Entscheidungen über virtuelle Maschine über das Entwerfen verleiht. Ein mögliches Heap -Design ist wie folgt:
Ein Griffpool, ein Objektpool. Die Referenz eines Objekts ist ein lokaler Zeiger auf den Griffpool. Die Vorteile dieses Designs sind der Sortierung von Haufenfragmenten förderlich. Wenn Sie Objekte im Objektpool bewegen, muss der Handlungsteil nur die neue Adresse des Zeigers auf das Objekt ändern. Der Nachteil besteht darin, dass jedes Mal, wenn eine Instanzvariable eines Objekts zugegriffen wird, zwei Zeiger durchlaufen werden muss.
2.5 Java Stack
Immer wenn ein Thread gestartet wird, weist die virtuelle Java -Maschine einen Java -Stapel zu. Ein Java -Stack besteht aus vielen Stapelrahmen, ein Stapelrahmen enthält den Zustand eines Java -Methodenaufrufs. Wenn ein Thread eine Java -Methode aufruft, drückt die virtuelle Maschine einen neuen Stapelrahmen in den Java -Stack des Threads. Wenn die Methode zurückkehrt, taucht der Stapelrahmen aus dem Java -Stack auf. Der Java -Stack speichert den Status der Java -Methodenaufrufe in Threads - einschließlich lokaler Variablen, Parameter, Rückgaberwerte und Zwischenergebnisse von Operationen usw. Java -Virtual -Maschinen haben keine Register, und deren Anweisungssatz verwendet einen Java -Stapel, um Zwischendaten zu speichern. Der Grund für dieses Design besteht darin, den Anweisungssatz der Java -virtuellen Maschine so kompakt wie möglich zu halten und die Implementierung der Java -Virtual Machine auf einer Plattform mit wenigen allgemeinen Registern zu erleichtern. Darüber hinaus hilft die stackbasierte Architektur auch, den Code von dynamischen Compilern und Instant-Compilern zu optimieren, die während der Laufzeit von bestimmten virtuellen Maschinen implementiert werden.
2.5.1 Stapelrahmen
Ein Stapelrahmen besteht aus einem lokalen variablen Bereich, einem Operand -Stapel und einem Rahmendatenbereich. Wenn eine virtuelle Maschine eine Java -Methode aufruft, erhält sie den lokalen variablen Bereich und die Operand -Stapelgröße dieser Methode aus den Typinformationen der entsprechenden Klasse und zuordnet den Stapelrahmenspeicher danach zu und drückt sie dann in den Java -Stapel.
2.5.1.1 Lokaler variabler Bereich
Der lokale variable Bereich ist in ein Array organisiert, das von 0 in Einheiten der Wortlänge gezählt wird. Die Bytecode -Anweisung verwendet die Daten darin über einen Index ab 0. Werte der Typen int, float, referenz und returnAddress belegen ein Element im Array, während Werte von Typen Byte, Short und Char in die Werte konvertiert werden, bevor sie im Array gespeichert werden, und auch ein Element belegen. Die Werte von Typen, die lange und doppelt zwei aufeinanderfolgende Begriffe im Array belegen.
2.5.1.2 Operand Stack
Wie der lokale variable Bereich ist auch der Operand -Stapel in ein Array in Wortlänge organisiert. Es greift über Standard-Stack Operations-Stack und Stack aus. Da auf den Programmzähler nicht direkt durch Programmanweisungen zugegriffen werden kann, erhalten die Anweisungen der Java Virtual Machine Operanden aus dem Operand -Stack, sodass der Betrieb eher auf dem Stapel als auf Registern basiert. Die virtuelle Maschine nimmt den Operand -Stack als Arbeitsbereich auf, da die meisten Anweisungen Daten von hier aus aufgeben, Vorgänge ausführen und das Ergebnis dann wieder in den Operand -Stapel weitergeben müssen.
2.5.1.3 Rahmendatenbereich
Zusätzlich zum lokalen variablen Bereich und zum Operand -Stack benötigen Java -Stack -Frames auch Rahmendatenbereiche, um die konstante Poolanalyse, eine normale Methode und Ausnahmemechanismen zu unterstützen. Immer wenn eine virtuelle Maschine eine Anweisung ausführen möchte, die konstante Pooldaten erfordert, greift sie über einen Zeiger auf den konstanten Pool im Rahmendatenbereich zu. Zusätzlich zur Analyse konstanter Pools hilft der Rahmendatenbereich auch der virtuellen Maschine, das normale Ende oder abnormale Abbruch der Java -Methoden zu bewältigen. Wenn die Rückgabe normalerweise endet, muss die virtuelle Maschine den Stapelrahmen der Methode wiederherstellen, in dem der Anruf initiiert wird, einschließlich der Festlegung des Programms, um auf die nächste Anweisung zu verweisen, die die Anrufmethode initiiert. Wenn die Methode einen Rückgabewert hat, muss die virtuelle Maschine sie in den Operand -Stapel der Methode einführen, die den Anruf initiiert. Um die Ausnahme von Ausnahmen während der Ausführung der Java -Methode zu bewältigen, enthält der Frame -Datenbereich auch einen Verweis auf die Ausnahmeetabelle dieser Methode.
2.6 Programmzähler
Für ein laufendes Java -Programm hat jeder Thread seinen Programmzähler. Programmzähler werden auch PC -Register genannt. Der Programmzähler kann sowohl einen lokalen Zeiger als auch einen Rückkehrer enthalten. Wenn ein Thread eine Java -Methode ausführt, ist der Wert des Programmzählers immer die Adresse der nächsten ausgeführten Anweisung. Die Adresse hier kann ein lokaler Zeiger oder ein Offset in der Methode -Bytecode relativ zur Methode Start -Anweisung sein. Wenn der Thread eine lokale Methode ausführt, ist der Wert des Programmzählers "undefiniert".
2.7 Lokalmethode Stack
Jede lokale Methodenschnittstelle verwendet einen lokalen Methodenstapel. Wenn ein Thread eine Java -Methode aufruft, erstellt die virtuelle Maschine einen neuen Stapelrahmen und drückt ihn in den Java -Stack. Wenn es eine lokale Methode aufruft, hält die virtuelle Maschine den Java -Stapel unverändert und drückt nicht mehr in den neuen Stapel im Thread -Java -Stapel. Die virtuelle Maschine verbindet einfach dynamisch und direkt die angegebene lokale Methode.
Der Methodenbereich und der Haufen werden von allen Threads in der Instanz der virtuellen Maschine geteilt. Wenn die virtuelle Maschine eine Klassendatei lädt, analysiert sie die Typinformationen aus den in der Klassendatei enthaltenen Binärdaten und platziert dann die Typinformationen in den Methodenbereich. Wenn das Programm ausgeführt wird, platziert die virtuelle Maschine alle vom Programm erstellten Objekte zur Laufzeit in den Haufen.
Wie bei anderen Laufzeitspeicherbereichen kann der Speicherbereich, der vom lokalen Methodenstapel besetzt ist, dynamisch erweitert oder nach Bedarf geschrumpft werden.
3 Ausführungsmaschine
In der Spezifikation "Virtual Machine" Java wird das Verhalten der Ausführungsmaschine unter Verwendung von Befehlssätzen definiert. Der Designer, der die Ausführungs -Engine implementiert, entscheidet, wie Bytecode ausgeführt wird. Die Implementierung kann interpretiert, zusammengestellt oder direkt mit Anweisungen auf dem Chip oder einer Mischung aus ihnen ausgeführt werden.
Die Ausführungsmaschine kann als abstrakte Spezifikation, eine konkrete Implementierung oder eine laufende Instanz verstanden werden. Abstrakte Spezifikationen verwenden Anweisungssätze, um das Verhalten der Ausführungsmaschine anzugeben. Eine bestimmte Implementierung kann eine Vielzahl verschiedener Technologien verwenden - einschließlich Software, Hardware oder einer Kombination aus Baumtechnologie. Die Ausführungsmaschine als Laufzeitinstanz ist ein Thread.
Jeder Thread eines laufenden Java -Programms ist eine Instanz einer unabhängigen Virtual Machine Execution Engine. Vom Anfang bis zum Ende des Thread -Lebenszyklus wird entweder Bytecode oder eine lokale Methode ausgeführt.
3.1 Anweisungssatz
Der Bytecode -Stream der Methode besteht aus einer Abfolge von Anweisungen einer virtuellen Java -Maschine. Jede Anweisung enthält einen Einzelbyte-Opcode, gefolgt von 0 oder mehr Operanden. Der Opcode repräsentiert die zu durchgeführte Operation; Der Operand bietet dem Java Virtual Machine zusätzliche Informationen zur Ausführung des Opcode. Wenn eine virtuelle Maschine eine Anweisung ausführt, kann die Elemente im aktuellen konstanten Pool, die Werte in der lokalen Variablen des aktuellen Rahmens oder die Werte oben im Operand -Stapel des aktuellen Rahmens verwendet werden.
Die abstrakte Ausführungs -Engine führt jeweils eine Bytecode -Anweisung aus. Jeder Thread (Ausführungs -Engine -Instanz) eines Programms, das in einer java -virtuellen Maschine ausgeführt wird, führt diesen Vorgang durch. Die Ausführungs -Engine erhält den Opcode und wenn der Opcode einen Operand hat, erhält er seinen Operanden. Es führt die vom Opcode und den folgende Operand angegebene Aktion aus und erhält dann den nächsten Opcode. Dieser Prozess der Ausführung von Bytecode wird fortgesetzt, bis der Thread abgeschlossen ist, und die Fertigstellung des Threads kann durch die Rückkehr aus seiner anfänglichen Methode gekennzeichnet werden oder die geworfene Ausnahme nicht erfassen.
4 lokale Methodenschnittstelle
Die lokale Java -Schnittstelle, auch JNI (JavanativeInterface) genannt, wird für die Portabilität vorbereitet. Die lokale Methodenschnittstelle ermöglicht es der lokalen Methode, Folgendes auszuführen:
Daten übergeben oder zurückgeben
Betriebsinstanzvariablen
Betreiben Sie Klassenvariablen oder rufen Sie Klassenmethoden auf
Operand -Array
Sperren Sie das Heap -Objekt
Laden Sie neue Klasse
Wirf eine Ausnahme
Fangen Sie die Ausnahme durch eine lokale Methode, die eine Java -Methode aufruft
Erfassen Sie eine asynchrone Ausnahme, die von virtueller Maschine ausgelöst wird
Zeigt an, dass ein Müllsammlerobjekt nicht mehr benötigt wird
Zusammenfassen
In dem oben genannten Artikel geht es um diesen Artikel über ein detailliertes Verständnis der Java Virtual Machine Architecture, und ich hoffe, dass es für alle hilfreich sein wird. Interessierte Freunde können weiterhin auf andere verwandte Themen auf dieser Website verweisen. Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen. Vielen Dank an Freunde für Ihre Unterstützung für diese Seite!