Im Java-Kompilierungssystem erfordert der Prozess der Umwandlung einer Java-Quellcodedatei in eine vom Computer ausführbare Maschinenanweisung zwei Kompilierungsschritte. Der erste Schritt besteht darin, die .java-Datei in eine .class-Datei zu konvertieren. Die zweite Stufe der Kompilierung ist der Prozess der Konvertierung von .class in Maschinenanweisungen.
Der erste Abschnitt der Kompilierung ist der Befehl javac.
In der zweiten Kompilierungsstufe interpretiert die JVM den Bytecode und übersetzt ihn in entsprechende Maschinenanweisungen, liest ihn einzeln ein und interpretiert die Übersetzung einzeln. Offensichtlich ist seine Ausführungsgeschwindigkeit nach der Interpretation und Ausführung zwangsläufig viel langsamer als die des ausführbaren binären Bytecode-Programms. Dies ist die Funktion des traditionellen JVM-Interpreters (Interpreter). Um dieses Effizienzproblem zu lösen, wurde die JIT-Technologie (Just-in-Time-Compilation) eingeführt.
Nach der Einführung der JIT-Technologie werden Java-Programme immer noch über den Interpreter interpretiert und ausgeführt. Wenn die JVM feststellt, dass eine bestimmte Methode oder ein Codeblock besonders häufig ausgeführt wird, betrachtet sie diese als „Hot Spot Code“. Dann übersetzt JIT einen Teil des „Hot Codes“ in Maschinencode, der sich auf die lokale Maschine bezieht, optimiert ihn und speichert dann den übersetzten Maschinencode für die nächste Verwendung zwischen.
Da ich den Inhalt der JIT-Kompilierung und Hotspot-Erkennung bereits in meiner ausführlichen Analyse der Java-Kompilierungsprinzipien vorgestellt habe, werde ich hier nicht näher darauf eingehen. In diesem Artikel wird hauptsächlich die Optimierung in JIT vorgestellt. Einer der wichtigsten Aspekte der JIT-Optimierung ist die Escape-Analyse.
Fluchtanalyse
Bezüglich des Konzepts der Escape-Analyse können Sie darauf verweisen, dass nicht alle Objekte und Arrays Speicher auf dem Heap allokieren. Ein Artikel, hier eine kurze Rezension:
Das grundlegende Verhalten der Escape-Analyse besteht darin, den dynamischen Bereich des Objekts zu analysieren: Wenn ein Objekt in einer Methode definiert ist, kann es von einer externen Methode referenziert werden, z. B. durch Übergabe an andere Stellen als Aufrufparameter, der als Methode bezeichnet wird Flucht.
Zum Beispiel der folgende Code:
public static StringBuffer craeteStringBuffer(String s1, String s2) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
Gib jdn zurück;
}
öffentlicher statischer String createStringBuffer(String s1, String s2) {
StringBuffer sb = new StringBuffer();
sb.append(s1);
sb.append(s2);
Return sb.toString();
}
Der jdn im ersten Code entkommt, aber der jdn im zweiten Code entkommt nicht.
Mithilfe der Escape-Analyse kann der Compiler den Code wie folgt optimieren:
1. Die Synchronisation entfällt. Wenn festgestellt wird, dass auf ein Objekt nur von einem Thread aus zugegriffen werden kann, wird die Synchronisierung für Vorgänge an diesem Objekt möglicherweise nicht in Betracht gezogen.
2. Konvertieren Sie die Heap-Zuweisung in eine Stapelzuweisung. Wenn ein Objekt in einer Unterroutine zugewiesen wird, sodass der Zeiger auf das Objekt niemals entweicht, ist das Objekt möglicherweise ein Kandidat für die Stapelzuweisung und nicht für die Heap-Zuweisung.
3. Separate Objekte oder Skalarersatz. Einige Objekte müssen für den Zugriff möglicherweise nicht als kontinuierliche Speicherstruktur vorhanden sein, sodass ein Teil (oder das Ganze) des Objekts möglicherweise nicht im Speicher, sondern in CPU-Registern gespeichert wird.
Wenn Java-Code ausgeführt wird, können Sie über JVM-Parameter angeben, ob die Escape-Analyse aktiviert werden soll,
-XX:+DoEscapeAnalysis: Zeigt an, dass die Escape-Analyse aktiviert ist
-XX:-DoEscapeAnalysis: Zeigt an, dass die Escape-Analyse standardmäßig seit JDK 1.7 gestartet wurde. Wenn Sie sie deaktivieren müssen, müssen Sie -XX:-DoEscapeAnalysis
angeben. Synchrones Auslassen Beim dynamischen Kompilieren eines synchronisierten Blocks kann der JIT-Compiler mithilfe der Escape-Analyse feststellen, ob auf das vom synchronisierten Block verwendete Sperrobjekt nur ein Thread zugreifen kann und es nicht für andere Threads freigegeben wurde. Wenn durch diese Analyse bestätigt wird, dass das vom synchronisierten Block verwendete Sperrobjekt nur für einen Thread zugänglich ist, desynchronisiert der JIT-Compiler diesen Teil des Codes beim Kompilieren des synchronisierten Blocks. Dieser Vorgang des Aufhebens der Synchronisation wird als Synchronisationsauslassung oder Sperrenbeseitigung bezeichnet. Wie zum Beispiel der folgende Code: öffentliche Leere f() { Object hollis = new Object(); synchronisiert(hollis) { System.out.println(hollis); } } Das Hollis-Objekt ist im Code gesperrt, aber der Lebenszyklus des Hollis-Objekts findet nur in der f()-Methode statt und andere Threads greifen nicht darauf zu, sodass es während der JIT-Kompilierungsphase optimiert wird. Optimiert auf: öffentliche Leere f() { Object hollis = new Object(); System.out.println(hollis); } Wenn die JIT bei Verwendung der Synchronisierung nach der Escape-Analyse feststellt, dass kein Thread-Sicherheitsproblem vorliegt, wird die Sperre aufgehoben. Skalarersatz Skalar bezieht sich auf Daten, die nicht in kleinere Daten zerlegt werden können. Der primitive Datentyp in Java ist skalar. Im Gegensatz dazu werden Daten, die zerlegt werden können, als Aggregat bezeichnet. Ein Objekt ist in Java ein Aggregat, da es in andere Aggregate und Skalare zerlegt werden kann.Wenn in der JIT-Phase durch die Escape-Analyse festgestellt wird, dass die Außenwelt nicht auf ein Objekt zugreifen kann, wird das Objekt nach der JIT-Optimierung in mehrere darin enthaltene Mitgliedsvariablen zerlegt und ersetzt. Bei diesem Vorgang handelt es sich um eine Skalarersetzung.
public static void main(String[] args) {
alloc();
}
private static void alloc() {
Punkt Punkt = neuer Punkt(1,2);
System.out.println("point.x="+point.x+"; point.y="+point.y);
}
Klassenpunkt{
private int x;
private int y;
}
Im obigen Code entgeht das Punktobjekt der Alloc-Methode nicht und das Punktobjekt kann in Skalare zerlegt werden. Dann erstellt JIT das Point-Objekt nicht direkt, sondern verwendet direkt zwei Skalare int x und int y, um das Point-Objekt zu ersetzen.
Der obige Code wird nach der Skalarersetzung zu:
private static void alloc() {
int x = 1;
int y = 2;
System.out.println("point.x="+x+"; point.y="+y);
}
Es ist ersichtlich, dass nach der Escape-Analyse der Aggregatmenge Point festgestellt wurde, dass diese nicht entkommen ist, und daher durch zwei Aggregatmengen ersetzt wurde. Was sind also die Vorteile der Skalarsubstitution? Das heißt, es kann die Heap-Speichernutzung erheblich reduzieren. Denn sobald keine Notwendigkeit besteht, Objekte zu erstellen, besteht auch keine Notwendigkeit, Heap-Speicher zuzuweisen.
Skalare Substitution bietet eine gute Grundlage für die Zuordnung auf dem Stapel.
Zuordnung auf Stapel
In der Java Virtual Machine ist es allgemein bekannt, dass Objekten Speicher im Java-Heap zugewiesen wird. Es gibt jedoch einen Sonderfall: Wenn nach der Escape-Analyse festgestellt wird, dass ein Objekt keine Escape-Methode hat, kann es für die Zuordnung auf dem Stapel optimiert werden. Dadurch entfällt die Notwendigkeit, Speicher auf dem Heap zuzuweisen, und die Garbage Collection entfällt.
Eine ausführliche Einführung in die Zuweisung auf dem Stapel finden Sie unter Nicht alle Objekte und Arrays weisen Speicher auf dem Heap zu. .
An dieser Stelle möchte ich kurz erwähnen, dass in bestehenden virtuellen Maschinen die Zuordnung auf dem Stapel nicht wirklich implementiert ist und Objekte und Arrays keinen Speicher auf dem Heap zuweisen. In unserem Beispiel wird das Objekt nicht auf dem Heap zugewiesen, sondern tatsächlich durch Skalarersetzung implementiert.
Die Fluchtanalyse ist nicht ausgereift
Das Papier zur Escape-Analyse wurde 1999 veröffentlicht, aber erst mit JDK 1.6 implementiert, und diese Technologie ist noch nicht sehr ausgereift.
Der Hauptgrund besteht darin, dass es keine Garantie dafür gibt, dass der Leistungsverbrauch der Escape-Analyse höher ist als der Leistungsverbrauch. Obwohl die Escape-Analyse Skalarsubstitution, Stapelzuweisung und Sperrenbeseitigung durchführen kann. Allerdings erfordert die Fluchtanalyse selbst auch eine Reihe komplexer Analysen, was eigentlich ein relativ zeitaufwändiger Prozess ist.
Ein extremes Beispiel ist, dass nach der Escape-Analyse festgestellt wird, dass kein Objekt nicht entkommt. Dann ist der Prozess der Escape-Analyse umsonst.
Obwohl diese Technologie noch nicht sehr ausgereift ist, ist sie auch ein sehr wichtiges Mittel in der Just-in-Time-Compiler-Optimierungstechnologie.
Das obige ist der detaillierte Inhalt vonWie man Escape in Java versteht. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!