Heim  >  Artikel  >  Java  >  Java Virtual Machine Learning – Klassenlademechanismus

Java Virtual Machine Learning – Klassenlademechanismus

黄舟
黄舟Original
2017-03-18 17:51:551293Durchsuche

Klassenlademechanismus

Der Lademechanismus ist der Prozess, bei dem die JVM die Klassendatei in den Speicher lädt, die Daten überprüft, konvertiert, analysiert und initialisiert und schließlich einen Java-Typ bildet, der direkt sein kann Wird von der JVM verwendet.

Eine Klasse beginnt mit dem Laden in den Speicher der virtuellen Maschine, bis sie aus dem Speicher entladen wird. Ihr Lebenszyklus umfasst: Laden, Überprüfung, Vorbereitung, Lösung. Es gibt sieben Phasen: Initialisierung, Verwendung und Entladen. wobei die drei Teile Verifizierung, Vorbereitung und Analyse gemeinsam als Links bezeichnet werden.

Die Reihenfolge der fünf Phasen des Ladens (Ladens), Verifizierens, Vorbereitens, Initialisierens und Entladens ist festgelegt. Der Ladevorgang der Klasse muss in dieser Reihenfolge beginnen Die Parsing-Phase ist nicht unbedingt erforderlich; sie kann in einigen Fällen nach der Initialisierung für die dynamische Laufzeitbindungsfunktion gestartet werden. Es ist zu beachten, dass diese Phasen normalerweise gemischt ausgeführt werden und normalerweise während der Ausführung einer Phase eine andere Phase aufrufen oder aktivieren.


Laden:

Die Ladephase ist eine Phase im „Klassenlademechanismus“. Diese Phase wird üblicherweise auch „Laden“ genannt und umfasst hauptsächlich:

1. Holen Sie sich den binären Bytestream, der diese Klasse definiert, über den „vollständigen Namen der Klasse“

2. Konvertieren Sie die durch den Bytestream dargestellte statische Speicherstruktur in Laufzeitdaten Bereichsstruktur

3. Generieren Sie ein java.lang.Class-Objekt, das diese Klasse im Java-Heap als Zugriffseintrag für diese Daten im Methodenbereich darstellt

Die Spezifikation der virtuellen Maschine gilt für „durch“. " Der vollständige Name der Klasse „So erhalten Sie den Binärbyte-Stream, der diese Klasse definiert“ gibt nicht an, dass der Binärstream aus einer lokalen Klassendatei abgerufen werden muss. Um genau zu sein, gibt er nicht an, wo und wie er abgerufen werden kann. Zum Beispiel:

Das Lesen aus einem Zip-Paket ist weit verbreitet und wird schließlich zur Grundlage für zukünftige JAR-, EAR- und WAR-Formate.

Aus dem Internet bezogen, gemeinsames Anwendungs-Applet.

Laufzeitberechnung und -generierung Die in diesem Szenario am häufigsten verwendete Technologie ist die dynamische Proxy-Technologie. In java.lang.reflect.Proxy wird ProxyGenerator.generateProxyClass zum Generieren der Binärdatei der Proxy-Klasse von $Prxoy verwendet eine bestimmte Schnittstelle.

wird aus anderen Formatdateien generiert. Dieses Szenario kommt relativ selten vor (z. B. SAP Netweaver). in die Datenbank, um die Verteilung des Programmcodes zwischen den Clustern abzuschließen.

Im Vergleich zu anderen Phasen des Klassenladevorgangs ist die Ladephase (vorbereitend gesprochen, die Aktion zum Erhalten des binären Bytestroms der Klasse in der Ladephase) die am besten kontrollierbare Phase während der Entwicklungsphase, weil die Ladephase Dies kann mit dem vom System bereitgestellten Klassenlader (ClassLoader) oder mit einem benutzerdefinierten Klassenlader erfolgen. Entwickler können die Erfassungsmethode des Bytestreams steuern, indem sie ihren eigenen Klassenlader definieren.

Nach Abschluss der Ladephase wird der binäre Bytestrom außerhalb der virtuellen Maschine im Methodenbereich gemäß dem von der virtuellen Maschine benötigten Format gespeichert. Das Datenspeicherformat im Methodenbereich wird durch die virtuelle Maschine definiert Maschinenimplementierung. Die virtuelle Maschine. Die spezifische Datenstruktur dieses Bereichs ist nicht angegeben. Anschließend wird ein Objekt der Klasse java.lang.Class im Java-Heap instanziiert. Dieses Objekt dient dem Programm als externe Schnittstelle für den Zugriff auf diese Datentypen im Methodenbereich. Teile der Ladephase und der Verknüpfungsphase (z. B. einige Aktionen zur Überprüfung des Bytecode-Dateiformats) sind verschachtelt. Die Ladephase ist noch nicht abgeschlossen und die Verknüpfungsphase hat möglicherweise begonnen, aber diese zwischen der Ladephase eingeklemmten Aktionen gehören noch dazu Die Verknüpfung der Etappeninhalte und die Startzeiten dieser beiden Etappen behalten weiterhin eine feste Reihenfolge bei.


Überprüfung:

Die Überprüfung ist der erste Schritt in der Verknüpfungsphase. Der Hauptzweck dieses Schritts besteht darin, sicherzustellen, dass die im Bytestrom der Klassendatei enthaltenen Informationen den Anforderungen der aktuellen virtuellen Maschine entsprechen Die Sicherheit der virtuellen Maschine selbst nicht gefährden.

Die Verifizierungsphase umfasst hauptsächlich vier Verifizierungsprozesse: Überprüfung des Dateiformats, Überprüfung der Metadaten, Überprüfung des Bytecodes und Überprüfung der Symbolreferenz.

1. Überprüfung des Dateiformats

Überprüfen Sie die Spezifikation des Klassendateiformats, zum Beispiel: ob die Klassendatei mit dem magischen 0xCAFEBABE beginnt, ob die Haupt- und Nebenversionsnummern innerhalb des Verarbeitungsbereichs von liegen die aktuelle virtuelle Maschine usw.

2. Metadatenüberprüfung

In dieser Phase wird eine semantische Analyse der durch den Bytecode beschriebenen Informationen durchgeführt, um sicherzustellen, dass die beschriebenen Informationen den Anforderungen der Java-Sprache entsprechen Spezifikation. Zu den Überprüfungspunkten können gehören: ob diese Klasse eine übergeordnete Klasse hat (mit Ausnahme von java.lang.Object sollten alle Klassen eine übergeordnete Klasse haben), ob diese Klasse eine Klasse erbt, die nicht vererbt werden darf (durch final geändert), und ob Die übergeordnete Klasse dieser Klasse ist eine abstrakte Klasse. Implementiert sie alle Methoden, die in der übergeordneten Klasse oder Schnittstelle implementiert werden müssen?

3. Bytecode-Überprüfung

Führen Sie eine Datenfluss- und Kontrollflussanalyse durch. In dieser Phase wird der Methodenkörper der Klasse überprüft und analysiert. Die Aufgabe dieser Phase besteht darin, sicherzustellen, dass die Methode der zu überprüfenden Klasse keine Aktionen ausführt Sicherheit der virtuellen Maschine während der Laufzeit. Stellen Sie beispielsweise sicher, dass die Typkonvertierung im Hauptteil der Zugriffsmethode gültig ist. Sie können beispielsweise ein Unterklassenobjekt einem Datentyp einer Unterklasse zuweisen. Stellen Sie sicher, dass der Sprungbefehl nicht zu Bytecode-Befehlen außerhalb des Methodenkörpers springt.

4. Überprüfung der Symbolreferenz

Ob der durch die Zeichenfolge in der Symbolreferenz beschriebene vollständig qualifizierte Name die entsprechende Klasse finden kann, die Zugänglichkeit der Klassen, Felder und Methoden in der Symbolreferenzklasse (private, protected, public, default) kann von der aktuellen Klasse aufgerufen werden.


Vorbereitung:

Die Vorbereitungsphase ist die Phase, in der Speicher für Klassenvariablen formal zugewiesen und der Anfangswert der Klassenvariablen festgelegt wird im Methodenbereich „distribute“ durchgeführt werden. Es gibt zwei Wissenspunkte, die zu diesem Zeitpunkt leicht verwirrend sind. Erstens umfasst die Speicherzuweisung zu diesem Zeitpunkt nur Klassenvariablen (statisch geänderte Variablen), keine Instanzvariablen, die dem Objekt gemeinsam instanziiert werden Java-Heap. Zweitens ist der hier erwähnte Anfangswert „normalerweise“ der Nullwert des Datentyps. Angenommen, eine Klassenvariable ist definiert als:

public static int value = 12;

Dann der Variablenwert ist Der Anfangswert nach der Vorbereitungsphase ist 0 statt 12, da noch keine Java-Methode ausgeführt wurde und die putstatic-Anweisung, die 123 den Wert zuweist, nach der Kompilierung des Programms in der Klassenkonstruktormethode () gespeichert wird . , daher wird die Aktion zum Zuweisen des Werts zu 12 nur während der Initialisierungsphase ausgeführt.

Unter den oben genannten „normalen Umständen“ ist der Anfangswert Null. Im Vergleich zu einigen Sonderfällen wird der Variablenwert geändert, wenn in der Feldattributtabelle des Klassenfelds ein ConstantValue-Attribut vorhanden ist Während der Vorbereitungsphase wird der obige Klassenvariablenwert auf den durch das ConstantValue-Attribut angegebenen Wert initialisiert und wie folgt definiert:

public static final int value = 123;

Beim Kompilieren wird javac generiert das ConstantValue-Attribut für den Wert. Während der Vorbereitung legt die virtuelle Bühnenmaschine den Wert entsprechend der ConstantValue-Einstellung auf 123 fest.


Analyse:

In der Analysephase werden Symbolreferenzen im Konstantenpool der virtuellen Maschine durch direkte Referenzen ersetzt.

Symbolreferenz: Eine symbolische Referenz ist eine Reihe von Symbolen zur Beschreibung des referenzierten Zielobjekts. Das Symbol kann jede Form eines Literals sein, solange das Ziel bei der Verwendung eindeutig lokalisiert werden kann. Symbolische Referenzen haben nichts mit dem von der virtuellen Maschine implementierten Speicherlayout zu tun und das referenzierte Zielobjekt muss nicht unbedingt in den Speicher geladen werden.

Direkte Referenz: Eine direkte Referenz kann ein Zeiger sein, der direkt auf das Zielobjekt zeigt, ein relativer Offset oder ein Handle, der das Ziel indirekt lokalisieren kann. Direkte Referenzen beziehen sich auf die Implementierung des Speicherlayouts einer virtuellen Maschine. Die direkten Referenzen, die aus derselben Symbolreferenz auf verschiedenen virtuellen Maschineninstanzen übersetzt werden, sind im Allgemeinen nicht identisch. Wenn eine direkte Referenz vorhanden ist, muss das Referenzziel bereits im Speicher vorhanden sein.

Die Spezifikation der virtuellen Maschine legt nicht den genauen Zeitpunkt fest, zu dem die Analysephase stattfindet. Sie erfordert lediglich die Ausführung von 13 Schritten: anewarry, checkcast, getfield, instanceof, invokeinterface, invokespecial, invokestatic, invokevirtual, multianewarray, new , putfield und putstatic werden vor den Bytecode-Anweisungen zum Betreiben von Symbolreferenzen zuerst analysiert, sodass die Implementierung der virtuellen Maschine je nach Bedarf beurteilt, ob die Symbolreferenzen im Konstantenpool verarbeitet werden, wenn die Klasse geladen wird Parsen Sie den Loader oder warten Sie, bis eine Symbolreferenz verwendet werden soll, bevor Sie sie analysieren.

Die Analyseaktion wird hauptsächlich für vier Arten von Symbolreferenzen durchgeführt: Klassen oder Schnittstellen, Felder, Klassenmethoden und Schnittstellenmethoden. Entspricht den vier Konstantentypen CONSTANT_Class_Info, CONSTANT_Fieldref_Info, CONSTANT_Methodef_Info und CONSTANT_InterfaceMethoder_Info im kompilierten Konstantenpool.

1. Analyse von Klassen und Schnittstellen

3. Analyse von Klassenmethoden

>

Initialisierung:

Die Initialisierungsphase der Klasse ist der letzte Schritt des Klassenladevorgangs. In der Vorbereitungsphase wurden den Klassenvariablen die Initialen zugewiesen Der vom System benötigte Wert besteht in der Initialisierungsphase darin, Klassenvariablen und andere Ressourcen gemäß dem subjektiven Plan zu initialisieren, den der Programmierer durch das Programm erstellt hat, oder es kann aus einer anderen Perspektive ausgedrückt werden: Die Initialisierungsphase ist der Prozess von Ausführen der Klassenkonstruktormethode (). Der Initialisierungsprozess wird in den folgenden vier Situationen ausgelöst:

1. Wenn die Klasse auf die vier Bytecode-Anweisungen new, getstatic, putstatic oder invokestatic stößt und nicht initialisiert wurde, muss sie zuerst ausgelöst werden Initialisierung. Die häufigsten Java-Codeszenarien, die diese vier Anweisungen generieren, sind: Verwenden des Schlüsselworts new zum Instanziieren eines Objekts, Lesen oder Festlegen eines statischen Felds einer Klasse (mit Ausnahme statischer Felder, die von final geändert und von in den Konstantenpool eingefügt wurden). des Compilers) ) und beim Aufruf statischer Methoden der Klasse.

2. Wenn Sie die Methode des java.lang.reflect-Pakets verwenden, um einen reflektierenden Aufruf an eine Klasse durchzuführen

3. Wenn festgestellt wird, dass ihre übergeordnete Klasse vorhanden ist nicht initialisiert wurde, müssen Sie zuerst die übergeordnete Klasse initialisieren

4. Wenn JVM startet, gibt der Benutzer eine Hauptklasse an, die ausgeführt werden soll (die Klasse, die die Hauptmethode enthält), und die virtuelle Maschine initialisiert diese Klasse zuerst

In der obigen Vorbereitungsphase public static int value = 12; In Vorbereitung Nach Abschluss der Phase ist der Wert von value 0 und die Klassenkonstruktormethode () wird in der Initialisierungsphase aufgerufen. Nach Abschluss der Phase beträgt der Wert von value 12.

* Die Methode des Klassenkonstruktors() wird vom Compiler automatisch generiert, indem er die Zuweisungsaktionen aller Klassenvariablen in der Klasse sammelt und die Anweisungen im statischen Anweisungsblock (statischer Block) zusammenführt Die Reihenfolge wird durch die Reihenfolge bestimmt, in der die Anweisungen in der Quelldatei erscheinen. In einem statischen Anweisungsblock kann nur auf Variablen zugegriffen werden, die nach dem statischen Anweisungsblock definiert wurden , aber nicht zugänglich.

* Die Klassenkonstruktormethode () unterscheidet sich von der Klassenkonstruktormethode (). Sie muss den übergeordneten Klassenkonstruktor nicht explizit aufrufen ist garantiert. Bevor die Methode () der Unterklasse ausgeführt wird, wurde die Methode () der übergeordneten Klasse ausgeführt. Daher muss die Klasse der ersten ausgeführten ()-Methode in der virtuellen Maschine java.lang.Object sein.

* Da die ()-Methode der übergeordneten Klasse zuerst ausgeführt wird, bedeutet dies, dass die in der übergeordneten Klasse definierten statischen Anweisungen Vorrang vor den Variablenzuweisungsoperationen der Unterklasse haben.

*()-Methode ist für Klassen oder Schnittstellen nicht erforderlich. Wenn in einer Klasse keine statischen Anweisungen und keine Variablenzuweisungsoperationen vorhanden sind, muss der Compiler für diese Klasse keine < clinit>()-Methode.

* Statische Anweisungsblöcke können nicht in Schnittstellen verwendet werden, aber was bei Schnittstellen und Klassen nicht möglich ist, ist, dass die Ausführung der ()-Methode der Schnittstelle nicht zuerst die Ausführung von ( )-Methode der übergeordneten Schnittstelle. Die übergeordnete Schnittstelle wird nur initialisiert, wenn die in der übergeordneten Schnittstelle definierten Variablen verwendet werden. Darüber hinaus führt die Implementierungsklasse der Schnittstelle während der Initialisierung nicht die Methode () der Schnittstelle aus.

* Die virtuelle Maschine stellt sicher, dass die ()-Methode einer Klasse in einer Multithread-Umgebung korrekt gesperrt und synchronisiert wird. Wenn mehrere Threads gleichzeitig eine Klasse initialisieren, wird dies nur ein Thread tun Dies ausführen Für die ()-Methode der Klasse müssen andere Threads blockieren und warten, bis der aktive Thread die Ausführung der ()-Methode abgeschlossen hat. Wenn die Methode () einer Klasse Vorgänge mit langer Laufzeit enthält, kann dies dazu führen, dass mehrere Prozesse blockiert werden.

Das Obige ist der Inhalt von Java Virtual Machine Learning – Klassenlademechanismus. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).

Verwandte Artikel:

Detaillierte Erklärung der Java Virtual Machine

Detailliertes Verständnis der Java Virtual Machine

Java Virtual Machine Learning – Zuweisung und Recycling von Objektspeicher

Java Virtual Machine Learning – Objektzugriff

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn