1. Grundkonzepte
Jedes Java -Programm erzeugt einen Java -Prozess. Jeder Java -Prozess kann einen oder mehrere Threads enthalten. Jeder Java -Prozess entspricht einer eindeutigen JVM -Instanz, jede JVM -Instanz entspricht einem Haufen, und jeder Thread hat seinen eigenen privaten Stapel. Alle Instanzen von Klassen (dh Objekte) oder Arrays (in Bezug auf das Array selbst, nicht Referenzen), die durch einen Prozess erstellt wurden, werden in den Haufen platziert und von allen Threads des Prozesses geteilt. Der zugewiesene Heap -Speicher in Java wird automatisch initialisiert, dh bei der Zuweisung von Speicher an ein Objekt werden die Variablen im Objekt initialisiert. Obwohl der Speicherplatz aller Objekte in Java im Heap zugewiesen wird, wird der Verweis auf dieses Objekt im Stapel zugewiesen, dh wenn ein Objekt erstellt wird, wird der Speicher auf dem Haufen und dem Stapel zugewiesen. Der im Heap zugewiesene Speicher speichert das erstellte Objekt selbst, während der im Stapel zugewiesene Speicher nur Verweise auf das Heap -Objekt speichert. Wenn das lokale Variable -Neue herauskommt, wird der Platz im Stapelraum und im Haufen Raum bereitgestellt. Wenn der lokale variable Lebenszyklus endet, wird der Stapelraum sofort recycelt, und der Haufenraum wartet darauf, dass GC recycelt.
Spezifisches Konzept: Das Gedächtnis eines JVM kann in drei Bereiche unterteilt werden: Haufen, Stapel und Methodenbereich (Methode, auch als statischer Bereich bezeichnet):
Stapelbereich:
1. Alle gespeicherten Objekte sind Objekte, und jedes Objekt enthält Informationen, die ihm entsprechen (der Zweck der Klasse besteht darin, Betriebsanweisungen zu erhalten).
2.JVM hat nur einen Haufen (Heap) und wird von allen Threads geteilt. Der Heap speichert keine grundlegenden Typen und Objektreferenzen, sondern nur das Objekt selbst und das Array selbst.
Stapelbereich:
1. Jeder Thread enthält einen Stapelbereich, der nur Verweise auf den grundlegenden Datentyp selbst und benutzerdefinierte Objekte speichert.
2. Die Daten (primitive Typ und Objektreferenz) in jedem Stapel sind privat und können nicht von anderen Stapeln zugegriffen werden.
3.. Der Stapel ist in 3 Teile unterteilt: grundlegender Typ variabler Bereich, Ausführungsumgebungskontext und Betriebsanweisungsbereich (Anweisungen für Betriebsbetrieb);
Methodenbereich (statischer Bereich):
1. von allen Threads geteilt. Der Methodenbereich enthält alle Klassen (Klasse bezieht sich auf den ursprünglichen Code der Klasse. Um ein Klassenobjekt zu erstellen, muss der Code der Klasse in den Methodenbereich geladen und initialisiert werden) und statische Variablen.
2. Der Methodenbereich enthält Elemente, die im gesamten Programm immer einzigartig sind, wie z. B. Klassen- und statische Variablen.
2. Beispieldemonstration
Appmain.java
Public Class Appmain // Beim Ausführen stellt JVM den gesamten Appmain -Code in den Methodenbereich {öffentliche statische Leere Main (String [] args) // Die Hauptmethode selbst wird im Methodenbereich platziert. {Sample test1 = Neue Probe ("Test 1"); // test1 ist eine Referenz. Wenn Sie also den Stapelbereich einfügen, ist die Probe ein benutzerdefiniertes Objekt, das in den Haufen platziert werden sollte. Probe test2 = neue Probe ("Test 2"); test1.printname (); test2.printname (); }} public class sample // Beim Ausführen stellt JVM alle Informationen von Appmain in den Methodenbereich { /** Beispielname* /privater Zeichenfolge Name; // Nach einer neuen Beispielinstanz wird die Namensreferenz im Stapelbereich platziert. Der entsprechende String -Objekt wird im Heap/** Konstruktor*/public sample (String name) {this .name = name; } /** Ausgabe* /public void printName () // Wenn kein Objekt vorhanden ist, wird die Druckmethode zusammen mit der Beispielklasse im Methodenbereich platziert. {System.out.println (Name); }}Starten Sie beim Ausführen des Programms zunächst einen Java Virtual Machine -Prozess. Dieser Prozess findet zunächst die Datei appmain.class aus dem ClassPath, liest die Binärdaten in der Datei und speichert dann die Klasseninformationen der Appmain -Klasse im Methodenbereich des Laufzeitbereichs. Dies ist der Ladevorgang der Appmain -Klasse.
Als nächstes lokalisiert die Java Virtual Machine die Bytecode der Main () -Methode der Appmain -Klasse im Methodenbereich und beginnt mit der Ausführung ihrer Anweisungen. Die erste Aussage dieser Main () -Methode lautet:
Die Codekopie lautet wie folgt:
Sample Test1 = neue Probe ("test1");
Der Ausführungsprozess dieser Erklärung:
1. Die virtuelle Java -Maschine fand die Typinformationen der Stichprobenklasse im Methodenbereich, aber es wurde nicht gefunden, da die Probenklasse nicht in den Methodenbereich geladen wurde (es ist hier zu sehen, dass die internen Klassen in Java separat existieren und am Anfang nicht mit der enthaltenden Klasse geladen und nicht geladen wird, bis es verwendet wird). Die virtuelle Java -Maschine lädt sofort die Beispielklasse und speichert die Beispiel -Klassentypinformationen im Methodenbereich.
2. Die virtuelle Java -Maschine weist zuerst einen Speicher für eine neue Beispielinstanz im Haufenbereich zu und speichert eine Speicheradresse in dem Methodenbereich, in dem die Informationen zum Beispielklassentyp im Speicher der Beispielinstanz gespeichert sind.
3. Im JVM -Prozess verfügt jeder Thread über einen Method -Call -Stack, mit dem während des Ausführens des Threads eine Reihe von Methodenaufrufprozessen verfolgt werden. Jedes Element im Stapel wird als Stapelrahmen bezeichnet. Immer wenn ein Thread eine Methode aufruft, wird ein neuer Frame in den Method -Stapel gedrückt. Die Frames hier werden verwendet, um die Parameter der Methode, der lokalen Variablen und der temporären Daten während des Betriebs zu speichern.
4. Test1 vor "=" ist eine Variable (eine Referenz auf ein Beispielobjekt), die in der Main () -Methode definiert ist, daher wird sie dem Java -Methode -Aufrufstapel des Haupt -Threads hinzugefügt, der die Main () -Methode ausführt. Und "=" zeigt diese Test1 -Variable auf die Probeninstanz im Haufenbereich.
5. Die JVM erstellt weiterhin eine weitere Beispielinstanz im Haufenbereich und fügt dem Methodenaufrufstapel der Hauptmethode eine Test2 -Variable hinzu, die auf die neue Beispielinstanz zeigt, die gerade im Haufenbereich erstellt wurde.
6. Die JVM führt nach seiner Methode ihre PrintName () -Methode aus. Wenn die java -virtuelle Maschine die methode test1.printname () ausführt, lokalisiert die Java -Virtual Machine die Beispielinstanz im Heap -Bereich basierend auf der Referenz, die von der lokalen Variablen -Test1 gehalten wird, und lokalisiert dann die Probenklassentypinformationen in der Methode anhand der Referenz, die von der Probeninstanz gehalten wurde, die Anweisungen in der Anleitung, die die Anweisungen für die Ausführung von PRINTNAME ().
III. Unterscheiden
Der Unterschied zwischen Haufen und Stapel in der Java -Sprache:
1. Stack und Heap sind beide Orte, die von Java verwendet werden, um Daten in RAM zu speichern. Im Gegensatz zu C ++ verwaltet Java automatisch Stapel und Haufen, und Programmierer können keine Stapel oder Haufen direkt einrichten.
2. Der Vorteil des Stapels besteht darin, dass die Zugangsgeschwindigkeit schneller als der Haufen ist, nur die Register, die sich direkt in der CPU befinden. Der Nachteil ist jedoch, dass die Datengröße und die Lebensdauer im Stapel deterministisch sein müssen und keine Flexibilität haben. Darüber hinaus können Stapeldaten gemeinsam genutzt werden (finden Sie in der folgenden Einführung Einzelheiten). Der Vorteil des Haufens besteht darin, dass er die Speichergröße dynamisch zuweisen kann und die Lebensdauer dem Compiler nicht im Voraus mitgeteilt werden muss. Der Müllsammler von Java sammelt automatisch die nicht mehr verwendeten Daten. Der Nachteil ist jedoch, dass der Speicher zur Laufzeit dynamisch zugewiesen werden muss, die Zugriffsgeschwindigkeit langsamer.
2 Datentypen in Java:
Eines sind die primitiven Typen mit 8 Kategorien, nämlich int, kurz, lang, byte, float, doppelt, boolean, char (beachten Sie, dass es keine grundlegende Art von String gibt). Diese Art von Definition wird durch eine Form wie int a = 3 definiert; lang B = 255L; und wird als automatische Variable bezeichnet. Automatische Variablen haben wörtliche Werte, keine Klasseninstanzen, dh sie sind keine Verweise auf Klassen, und es gibt hier keine Klasse. Zum Beispiel int a = 3; Hier ist A eine Referenz, die auf den INT -Typ zeigt und auf den wörtlichen Wert von 3. hinweist. Aufgrund der Größe und der Lebensdauer dieser wörtlichen Daten werden diese wörtlichen Werte in einem Programmblock fest definiert, und der Feldwert verschwindet nach dem Ausflug des Programmblocks) und existiert im Stapel, um die Geschwindigkeit zu verfolgen.
Der Stack hat eine sehr wichtige Funktion: Die im Stapel vorhandenen Daten können geteilt werden. Angenommen, wir definieren gleichzeitig: int a = 3; int b = 3; Der Compiler verarbeitet zuerst int a = 3; Zuerst erzeugt es eine Referenz mit einer Variablen A im Stapel und findet dann heraus, ob es eine Adresse mit einem wörtlichen Wert von 3 gibt. Wenn sie nicht gefunden wird, öffnet sie eine Adresse mit dem wörtlichen Wert von 3 und dann auf die Adresse von 3. Dann verarbeiten int b = 3; Nachdem die Referenzvariable von B erstellt wurde, wird B im Stapel bereits ein wörtlicher Wert von 3 vorhanden, sondern auf diese Weise direkt auf die Adresse von 3 hingewiesen. A und B zeigen beide gleichzeitig auf 3.
Dieser Hinweis auf wörtliche Werte unterscheidet sich von der von Klassenobjekten. Unter der Annahme, dass die Referenzen von zwei Klassenobjekten gleichzeitig auf ein Objekt verweisen, spiegelt die andere Objektreferenzvariable diese Änderung sofort wider. Stattdessen führt die Änderung des Wertes durch eine wörtliche Referenz nicht zu einem entsprechenden Wert, dass ein weiterer Wert geändert wird. Wie im obigen Beispiel, nachdem wir die Werte von A und B definiert haben, sei a = 4; Dann ist B nicht gleich 4 oder in einem Inneren des Compilers, wenn A = 4 angetroffen wird, wird es erneut suchen, ob im Stapel einen wörtlichen Wert von 4 vorhanden ist. Wenn nicht, öffnen Sie die Adresse erneut, um den Wert von 4 zu speichern. Wenn es bereits vorhanden ist, zeigen Sie direkt A auf diese Adresse. Daher wirkt sich die Wertänderung A nicht auf den Wert b aus.
Ein anderer Typ sind Verpackungsklassendaten wie Ganzzahl, String, Doppel usw., die die entsprechenden grundlegenden Datentypen umwickeln. Alle diese Klassendaten sind im Haufen vorhanden. Java verwendet die neue () Anweisung, um den Compiler anzuzeigen, und erstellt nur nach Bedarf dynamisch zur Laufzeit. Daher ist er flexibler, aber der Nachteil ist, dass es mehr Zeit in Anspruch nimmt.
4. Zusammenfassung
Die Java -Speicherzuweisungsstruktur ist immer noch sehr klar. Wenn Sie es gründlich verstehen möchten, können Sie JVM-bezogene Bücher überprüfen. In Java ist das String -Objekt am schwierigsten an der Speicherzuweisung. Aufgrund seiner besonderen Natur sind viele Programmierer anfällig für Verwirrung. Ich werde es im nächsten Artikel ausführlich erklären.