Heim  >  Artikel  >  Java  >  Ausführliche Erklärung des Java-Speichermodells mit Bildern und Text

Ausführliche Erklärung des Java-Speichermodells mit Bildern und Text

尚
nach vorne
2019-11-30 16:27:262263Durchsuche

Ausführliche Erklärung des Java-Speichermodells mit Bildern und Text

1. Überblick

Multitasking und hohe Parallelität sind einer der wichtigen Indikatoren zur Messung der Leistungsfähigkeit von ein Computerprozessor. Um die Leistung eines Servers zu messen, ist im Allgemeinen der Indikator „Transaktionen pro Sekunde“ (TPS) anschaulicher. Er stellt die durchschnittliche Anzahl von Anfragen dar, auf die der Server in einer Sekunde antworten kann, und der TPS-Wert steht im Zusammenhang mit den Parallelitätsfähigkeiten des Programms hängen sehr eng zusammen. Bevor wir das Java-Speichermodell und die Threads diskutieren, wollen wir kurz die Effizienz und Konsistenz der Hardware vorstellen. (Empfohlen: Java-Video-Tutorial)

2. Hardware-Effizienz und -Konsistenz

Aufgrund des Speichergeräts des Computers Zwischen dem Arbeitsspeicher und der Rechenleistung des Prozessors besteht eine Lücke von mehreren Größenordnungen, daher müssen moderne Computersysteme als Puffer dazwischen eine Cache-Schicht (Cache) mit einer Lese- und Schreibgeschwindigkeit hinzufügen, die möglichst nahe an der Rechengeschwindigkeit des Prozessors liegt Pufferung: Kopieren Sie die für die Operation benötigten Daten in den Cache, damit die Operation schnell ausgeführt werden kann. Wenn die Operation abgeschlossen ist, werden sie vom Cache wieder in den Speicher synchronisiert auf langsames Lesen und Schreiben im Speicher warten.

Cache-basierte Speicherinteraktion löst den Geschwindigkeitskonflikt zwischen Prozessor und Speicher, führt jedoch zu einem neuen Problem: Cache-Kohärenz. In einem Multiprozessorsystem verfügt jeder Prozessor über einen eigenen Cache und sie teilen sich den gleichen Hauptspeicher.

Wie in der folgenden Abbildung dargestellt: Mehrere Prozessor-Rechenaufgaben erfordern denselben Hauptspeicher, und es ist ein Protokoll erforderlich, um die Datenkonsistenz sicherzustellen. Zu diesen Protokollen gehören MSI, MESI, MOSI und Dragon Protocol. Die im Java Virtual Machine-Speichermodell definierten Speicherzugriffsvorgänge sind mit den Hardware-Cache-Zugriffsvorgängen vergleichbar. Das Java-Speichermodell wird später vorgestellt.

Ausführliche Erklärung des Java-Speichermodells mit Bildern und Text

Um die Recheneinheit im Prozessor voll auszunutzen, kann der Prozessor außerdem eine Out-Of-Order-Ausführung des Eingabecodes durchführen ) Bei der Optimierung ordnet der Prozessor die Ergebnisse des in der falschen Reihenfolge ausgeführten Codes nach der Berechnung neu an, um die Genauigkeit der Ergebnisse sicherzustellen. Ähnlich wie die Out-of-Order-Ausführungsoptimierung des Prozessors verfügt auch der Just-in-Time-Compiler der Java Virtual Machine über eine ähnliche Optimierung der Befehlsneuordnung (Instruction Recorder).

3. Java-Speichermodell

Dieses Modell muss streng genug definiert werden Gleichzeitige Vorgänge verursachen keine Mehrdeutigkeit. Sie müssen jedoch auch locker genug sein, damit die Implementierung der virtuellen Maschine über genügend freien Speicherplatz verfügt, um verschiedene Funktionen der Hardware (Register, Caches usw.) zu nutzen und so eine bessere Ausführungsgeschwindigkeit zu erzielen. Nach einer langen Zeit der Überprüfung und Korrektur ist das Java-Speichermodell seit der Veröffentlichung von JDK1.5 ausgereifter und verbessert worden.

3.1 Hauptspeicher und Arbeitsspeicher

Das Hauptziel des Java-Speichermodells besteht darin, die Zugriffsregeln für jede Variable im Programm zu definieren, also zu speichern die Variablen im Speicher der virtuellen Maschine und Details auf niedriger Ebene wie das Abrufen von Variablen aus dem Speicher. Die hier verwendeten Variablen unterscheiden sich von den in der Java-Programmierung erwähnten Variablen. Sie umfassen Instanzfelder, statische Felder und Elemente, die Array-Objekte bilden, jedoch keine lokalen Variablen und Methodenparameter. Letztere sind für den Thread privat und werden nicht gemeinsam genutzt. .

Das Java-Speichermodell schreibt vor, dass alle Variablen im Hauptspeicher gespeichert werden und jeder Thread über einen eigenen Arbeitsspeicher verfügt (der zuvor mit dem Cache des Prozessors verglichen werden kann). Der Thread wird im Hauptspeicher gespeichert. Alle Operationen (Lesen, Zuweisen) der Variablen durch den Thread müssen im Arbeitsspeicher ausgeführt werden, und Variablen im Hauptspeicher können nicht direkt gelesen oder geschrieben werden.

Verschiedene Threads können nicht direkt auf die Variablen im Arbeitsspeicher des anderen zugreifen. Die Übertragung von Variablenwerten zwischen Threads muss im Hauptspeicher erfolgen. Die interaktive Beziehung zwischen Threads, Hauptspeicher und Arbeitsspeicher wird angezeigt in der Abbildung unten und Das Bild oben ist sehr ähnlich.

Ausführliche Erklärung des Java-Speichermodells mit Bildern und Text

Der Hauptspeicher und der Arbeitsspeicher haben hier nicht die gleiche Speicherteilungsebene wie der Java-Heap, der Stapel und der Methodenbereich des Java-Speicherbereichs.

3.2 Inter-Memory-Interaktion

Über das spezifische Interaktionsprotokoll zwischen Hauptspeicher und Arbeitsspeicher, d. h. wie eine Variable vom Hauptspeicher in den Arbeitsspeicher kopiert wird und So kopieren Sie es vom Hauptspeicher in den Arbeitsspeicher: Um die Details der Synchronisierung des Arbeitsspeichers mit dem Hauptspeicher zu implementieren, definiert das Java-Speichermodell die folgenden acht auszuführenden Operationen:

1 Speicher, der eine Variable als exklusiven Thread-Status identifiziert.

2. Entsperren (entsperren): Wirkt auf die Hauptspeichervariable, um eine Variable freizugeben, die sich in einem gesperrten Zustand befindet. Nur die freigegebene Variable kann von anderen Threads gesperrt werden.

3. Lesen (Lesen): Wirkt auf die Hauptspeichervariable und überträgt einen Variablenwert aus dem Hauptspeicher in den Arbeitsspeicher des Threads, damit er von der nachfolgenden Ladeaktion verwendet werden kann

4. Laden: Wirkt auf Variablen im Arbeitsspeicher. Der durch den Lesevorgang aus dem Hauptspeicher erhaltene Variablenwert wird in eine Kopie der Variablen im Arbeitsspeicher eingefügt.

5. Verwendung (Verwendung): Wirkt auf Variablen im Arbeitsspeicher und übergibt einen Variablenwert im Arbeitsspeicher an die Ausführungs-Engine, wenn die virtuelle Maschine auf eine Bytecode-Anweisung stößt, die den Wert des verwenden muss Die Variable führt diesen Vorgang aus.

6. Zuweisen (Zuweisung): Wirkt auf eine Variable im Arbeitsspeicher. Sie weist einen von der Ausführungs-Engine empfangenen Wert einer Variablen im Arbeitsspeicher zu zu einer Variablen. Führen Sie diesen Vorgang aus, wenn Sie dazu aufgefordert werden.

7. Store (Speicher): Wirkt auf Variablen im Arbeitsspeicher und überträgt den Wert einer Variablen im Arbeitsspeicher für nachfolgende Schreibvorgänge in den Hauptspeicher.

8. Wirkt auf Variablen im Hauptspeicher. Es überträgt den Speichervorgang vom Wert einer Variablen im Arbeitsspeicher auf eine Variable im Hauptspeicher.

Wenn Sie eine Variable vom Hauptspeicher in den Arbeitsspeicher kopieren möchten, müssen Sie die Lese- und Ladevorgänge nacheinander ausführen. Wenn Sie die Variable vom Arbeitsspeicher zurück in den Hauptspeicher synchronisieren möchten , müssen Sie die Lese- und Ladevorgänge nacheinander ausführen. Führen Sie die Speicher- und Schreibvorgänge aus.

Das Java-Speichermodell erfordert lediglich, dass die oben genannten Vorgänge der Reihe nach ausgeführt werden müssen, es gibt jedoch keine Garantie dafür, dass sie kontinuierlich ausgeführt werden müssen. Das heißt, zwischen Lesen und Laden sowie zwischen Speichern und Schreiben können andere Anweisungen eingefügt werden. Beim Zugriff auf die Variablen a und b im Hauptspeicher ist beispielsweise die Reihenfolge „a lesen“, „b lesen“, „b laden“ und „a laden“ möglich. Das Java-Speichermodell schreibt außerdem vor, dass beim Ausführen der oben genannten acht Grundoperationen die folgenden Regeln erfüllt sein müssen:

1 Einer der Lese- und Lade-, Speicher- und Schreibvorgänge darf nicht alleine auftreten

2. Ein Thread darf seine letzte Zuweisungsoperation nicht verwerfen, d. h. Variablen müssen mit dem Hauptspeicher synchronisiert werden, nachdem sie im Arbeitsspeicher geändert wurden.

3. Ein Thread darf ohne Grund keine Daten aus dem Arbeitsspeicher zurück in den Hauptspeicher synchronisieren (es wurde kein Zuweisungsvorgang durchgeführt).

4. Eine neue Variable kann nur im Hauptspeicher erstellt werden und eine nicht initialisierte (Laden oder Zuweisen) Variable darf nicht direkt im Arbeitsspeicher verwendet werden. Das heißt, bevor Nutzungs- und Speichervorgänge für eine Variable ausgeführt werden, müssen zunächst Zuweisungs- und Ladevorgänge ausgeführt werden.

5. Nur ein Thread darf gleichzeitig eine Variable sperren.

6 Der Wert dieser Variablen im Speicher muss erneut ausgeführt werden. Lade- oder Zuweisungsvorgang, um den Variablenwert zu initialisieren, bevor die Ausführungs-Engine diese Variable verwendet

7. Wenn eine Variable nicht zuvor durch den Sperrvorgang gesperrt wurde Es ist nicht zulässig, den Vorgang zu entsperren. Es ist auch nicht zulässig, eine von anderen Threads gesperrte Variable zu entsperren.

8. Bevor eine Entsperroperation für eine Variable durchgeführt wird, muss die Variable mit dem Hauptspeicher synchronisiert werden (Speicher- und Schreiboperationen durchführen).

3.3 Neuordnung

Um die Leistung bei der Ausführung eines Programms zu verbessern, ordnen Compiler und Prozessoren häufig Anweisungen neu. Die Neuordnung ist in drei Typen unterteilt:

1. Compiler-optimierte Neuordnung. Der Compiler kann die Ausführungsreihenfolge von Anweisungen neu anordnen, ohne die Semantik eines Single-Thread-Programms zu ändern.

2. Parallele Neuordnung auf Befehlsebene. Moderne Prozessoren nutzen Parallelität auf Befehlsebene, um die Ausführung mehrerer Befehle zu überlappen. Wenn keine Datenabhängigkeiten bestehen, kann der Prozessor die Reihenfolge ändern, in der Anweisungen den Maschinenanweisungen entsprechen.

3. Neuordnung des Speichersystems. Da der Prozessor Cache sowie Lese- und Schreibpuffer verwendet, kann dies dazu führen, dass Lade- und Speichervorgänge scheinbar nicht in der richtigen Reihenfolge ausgeführt werden.

Vom Java-Quellcode bis zur endgültigen tatsächlich ausgeführten Befehlssequenz werden die folgenden drei Neuordnungen vorgenommen:

Ausführliche Erklärung des Java-Speichermodells mit Bildern und TextUm die Speichersichtbarkeit sicherzustellen, generiert der Java-Compiler die Befehlssequenz Gegebenenfalls werden Anweisungen zur Speicherbarriere eingefügt, um bestimmte Arten der Neuordnung von Prozessoren zu deaktivieren. Das Java-Speichermodell unterteilt Speicherbarrieren in vier Typen: LoadLoad, LoadStore, StoreLoad und StoreStore:

Ausführliche Erklärung des Java-Speichermodells mit Bildern und TextFür weitere Java-Kenntnisse beachten Sie bitte die Spalte Java Basic Tutorial.

Das obige ist der detaillierte Inhalt vonAusführliche Erklärung des Java-Speichermodells mit Bildern und Text. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen