Die Java -Speicherzuweisung und -verwaltung sind eine der Kerntechnologien von Java. Wir haben zuvor das Wissen über Javas Speichermanagement, Speicherleckage und Java -Müllsammlung vorgestellt. Heute werden wir wieder tief in den Java -Kern eingehen und das Wissen von Java in Gedächtnisallokation ausführlich vorstellen. Im Allgemeinen wird Java bei der Zuweisung von Speicher die folgenden Bereiche einbeziehen:
◆ Register: Wir können es im Programm nicht kontrollieren
◆ Stack: Speichert grundlegende Arten von Daten und Verweise auf Objekte, das Objekt selbst wird jedoch nicht im Stapel gespeichert, sondern im Heap gespeichert (das Objekt, das aus neu stammt)
◆ Heap: Daten speichern, die mit neuem generierten Daten speichern
◆ Statische Domäne: Statische Mitglieder, die in einem mit statischen definierten Objekt gespeichert sind
◆ Ständiger Pool: Ladenkonstanten
◆ Nicht-RAM-Speicher: Permanenter Speicherplatz wie Festplatte
Stapel in der Java -Speicherzuweisung
Einige grundlegende Arten von variablen Daten, die in der Funktions- und Referenzvariablen des Objekts definiert sind, werden im Stapelspeicher der Funktion zugewiesen.
Wenn eine Variable in einem Codeblock definiert wird, weist Java Speicherplatz für die Variable im Stapel zu. Wenn die Variable aus dem Umfang verlässt, löst Java den für die Variablen zugewiesenen Speicherraum automatisch frei, und der Speicherplatz kann sofort separat verwendet werden. Die Datengröße und der Lebenszyklus im Stapel sind sicher, und diese Daten verschwinden, wenn keine Bezugnahme auf die Daten zeigt.
Haufen in der Java -Speicherzuweisung
Der Heap -Speicher wird verwendet, um Objekte und Arrays zu speichern, die von New erstellt wurden. Der im Heap zugewiesene Speicher wird vom automatischen Müllsammler der Java Virtual Machine verwaltet.
Nachdem ein Array oder Objekt im Heap erzeugt wurde, kann im Stapel eine spezielle Variable definiert werden, so dass der Wert dieser Variablen im Stapel gleich der ersten Adresse des Arrays oder Objekts im Heap -Speicher ist, und die Variable im Stapel wird zu einer Referenzvariablen für das Array oder Objekt. Eine Referenzvariable entspricht einem Namen, der einem Array oder Objekt gegeben wird. Sie können die Referenzvariablen im Stapel im Programm verwenden, um auf das Array oder Objekt im Haufen zuzugreifen. Eine Referenzvariable entspricht einem Namen, der einem Array oder Objekt gegeben wurde.
Referenzvariablen sind gewöhnliche Variablen, die beim Definieren auf dem Stapel zugewiesen werden. Referenzvariablen werden veröffentlicht, nachdem das Programm außerhalb seines Geltungsbereichs ausgeführt wird. Das Array und das Objekt selbst werden im Haufen zugewiesen. Auch wenn das Programm außerhalb des Codeblocks läuft, in dem die Anweisungen, mit denen neu das Array oder Objekt generiert wird, befinden, wird der Speicher, der vom Array und Objekt selbst besetzt ist, nicht freigegeben. Das Array und das Objekt werden nur zu Müll, wenn keine Referenzvariable darauf hinweist und nicht verwendet werden kann, sondern dennoch den Speicherraum einnehmen. Es wird vom Müllsammler zu einer unsicheren Zeit gesammelt (freigegeben). Dies ist auch der Grund, warum Java mehr Erinnerung annimmt.
Tatsächlich verweisen Variablen im Stapel auf Variablen im Heap -Speicher, der Zeiger in Java ist!
Haufen und Stapel
Javas Heap ist ein Laufzeitbereich, aus dem Objekte Platz zuweisen. Diese Objekte werden durch Anweisungen wie New, Newarray, Neuarray und Multianewarray festgelegt. Sie müssen nicht ausdrücklich den Programmcode veröffentlicht. Der Haufen ist für die Müllsammlung verantwortlich. Der Vorteil des Haufens besteht darin, dass er die Speichergröße dynamisch zuordnen kann und dem Compiler nicht im Voraus mitteilen muss, da er zur Laufzeit dynamisch Speicher zuteilt. Der Müllsammler von Java sammelt automatisch die nicht mehr verwendeten Daten. Der Nachteil ist jedoch, dass die Zugriffsgeschwindigkeit langsamer ist, weil er zur Laufzeit dynamisch Speicher zuordnen muss.
Der Vorteil des Stacks besteht darin, dass die Zugangsgeschwindigkeit schneller als der Haufen ist, der nur die Register an zweiter Stelle steht und die Stapeldaten gemeinsam genutzt werden können. Der Nachteil ist jedoch, dass die Datengröße und die Lebensdauer im Stapel deterministisch sein müssen und keine Flexibilität haben. Der Stapel speichert hauptsächlich einige grundlegende Arten von variablen Daten (int, kurz, lang, byte, float, doppelt, boolean, char) und Objekthandles (Referenzen).
Eine sehr wichtige Spezialmerkmal des Stacks ist, dass die im Stapel vorhandenen Daten gemeinsam genutzt werden können. Angenommen, wir definieren gleichzeitig:
Java -Code
int a = 3;
int b = 3;
Der Compiler verarbeitet zuerst int a = 3; Zuerst erstellt es eine Referenz im Stapel mit einer Variablen A und findet dann heraus, ob im Stapel einen Wert von 3 vorhanden ist. Wenn es nicht gefunden wird, speichert es 3 und verarbeiten Sie dann int B = 3; Nachdem die Referenzvariable von B erstellt wurde, da im Stapel bereits ein Wert von 3 vorhanden ist, wird B direkt auf 3 gezeigt. Auf diese Weise verweisen A und B beide gleichzeitig auf 3.
Zu diesem Zeitpunkt ist, wenn a = 4 wieder eingestellt ist; Dann sucht der Compiler erneut, ob im Stapel einen Wert von 4 Wert aufweist. Wenn nicht, speichern Sie 4 und Punkt A bis 4; Wenn es bereits vorhanden ist, weisen Sie sich direkt auf diese Adresse an. Daher wirkt sich die Wertänderung A nicht auf den Wert b aus.
Es ist zu beachten, dass sich diese Teile von Daten von der Freigabe von Referenzen aus zwei Objekten unterscheidet, die gleichzeitig auf ein Objekt zeigen, da in diesem Fall die Änderung von A nicht beeinflusst wird, was der Compiler für den Speicherplatz förderlich ist. Eine Objektreferenzvariable verändert den internen Status dieses Objekts und wirkt sich auf eine andere Objektreferenzvariable aus.
Java -Code
1.Int i1 = 9;
2.Int i2 = 9;
3.int i3 = 9;
4. public statische endgültige int1 = 9;
5. public statische endgültige int2 = 9;
6. public statische endgültige int3 = 9;
Für Mitgliedsvariablen und lokale Variablen: Die Mitgliedsvariablen sind in der Methode und der Klasse definierten Variablen; Lokale Variablen sind Variablen, die in der Methode oder im Anweisungsblock definiert sind. Lokale Variablen müssen initialisiert werden.
Formale Parameter sind lokale Variablen, und die Daten lokaler Variablen sind im Stapelspeicher vorhanden. Lokale Variablen im Stapelspeicher verschwinden, wenn die Methode verschwindet.
Mitgliedervariablen werden in Objekten im Haufen gespeichert und vom Müllsammler gesammelt.
Wie im folgenden Code:
Java -Code
Klasse Geburtsdatum {privater Int Day; privat int monat; privates Int -Jahr; public birthdate (int d, int m, int y) {day = d; Monat = m; Jahr = y; } ausgelassen, setze Methode ……} public class Test {public static void main (String args []) {int date = 9; Test Test = neuer Test (); test.change (Datum); BirthDate D1 = New BirthDate (7,7,1970); } public void Change1 (int i) {i = 1234; }Für den obigen Code ist Datum eine lokale Variable, i, d, m, y sind alle formalen Parameter als lokale Variablen, und Tag, Monat und Jahr sind Mitgliedsvariablen. Lassen Sie uns die Änderungen während der Codeausführung analysieren:
1. Die Hauptmethode beginnt mit der Ausführung: int Datum = 9;
Datum lokale Variablen, Grundtypen, Referenzen und Werte sind im Stapel vorhanden.
2. Test Test = neuer Test ();
Der Test ist eine Objektreferenz, die auf dem Stapel vorhanden ist und das Objekt (New Test ()) auf dem Haufen vorhanden ist.
3.. Test.Change (Datum);
I ist eine lokale Variable, und die Referenz und der Wert sind im Stapel vorhanden. Wenn die Methodenänderung ausgeführt wird, werde ich aus dem Stapel verschwinden.
4. Birthdate D1 = New Birthdate (7,7,1970);
D1 ist eine Objektreferenz und existiert im Stapel. Objekte (New Birthdate ()) existieren im Haufen, wobei D, M, y lokale Variablen sind, die im Stapel gespeichert sind, und ihre Typen die Grundtypen sind, sodass ihre Daten auch im Stapel gespeichert werden. Tag, Monat, Jahr sind Mitgliedsvariablen und werden im Haufen (New Birthdate ()) gespeichert. Wenn der Geburtsdatumkonstruktor ausgeführt wird, verschwindet D, M, Y aus dem Stapel.
5. Nach der Ausführung der Hauptmethode verschwindet die Datumsvariable, der Test und die D1 -Referenz aus dem Stapel, und der neue Test () wird New Birthdate () auf die Müllsammlung warten.
Konstanter Pool
Konstante Pools beziehen sich auf einige Daten, die während der Kompilierungsperiode ermittelt und in der kompilierten .CLASS -Datei gespeichert werden.
Zusätzlich zur Eindämmung der konstanten Werte (endgültig) verschiedener Grundtypen (z. B. int, lang usw.) und Objekttypen (wie String und Arrays), die im Code definiert sind, enthält es auch einige symbolische Referenzen in Textform, wie z. B.:
◆ Die vollständig qualifizierten Namen von Klassen und Schnittstellen;
◆ Der Name und Deskriptor des Feldes;
◆ Methoden und Namen und Deskriptoren.
Wenn die Kompilierungszeit erstellt wurde (direkt in doppelten Zitaten definiert), wird sie im konstanten Pool gespeichert, und wenn sie durch die Laufzeit (von neu) bestimmt werden kann, wird er im Haufen gespeichert. Für Zeichenfolgen mit Gleichen befindet sich immer nur eine Kopie im konstanten Pool und mehrere Kopien im Haufen.
String sind spezielle Verpackungsdaten. Kann verwendet werden:
Java -Code
String str = new String ("ABC"); String str = "ABC";Es gibt zwei Formen zu erstellen. Die erste besteht darin, New () ein neues Objekt zu erstellen, das im Haufen gespeichert wird. Jedes Mal, wenn es aufgerufen wird, wird ein neues Objekt erstellt. Der zweite Typ besteht darin, zuerst eine variable STR zum Objekt der String -Klasse im Stapel zu erstellen und dann eine symbolische Referenz zu verwenden, um herauszufinden, ob es im String Constant Pool "ABC" gibt. Wenn nicht, speichern Sie "ABC" in den String Constant Pool und lassen Sie String auf "ABC" zeigen. Wenn es bereits "ABC" vorhanden ist, lassen Sie STR direkt auf "ABC" verweisen.
Verwenden Sie beim Vergleichen, ob die Werte in der Klasse gleich sind, die Equals () -Methode; Wenn Sie testen, ob die Referenzen der beiden Wrapper -Klassen auf dasselbe Objekt deuten, verwenden Sie == und verwenden Sie das folgende Beispiel, um die obige Theorie zu veranschaulichen.
Java -Code
String str1 = "abc"; String str2 = "abc"; System.out.println (str1 == str2); //WAHR
Es ist ersichtlich, dass Str1 und Str2 auf dasselbe Objekt verweisen.
Java -Code
String str1 = new String ("abc"); String str2 = new String ("ABC"); System.out.println (str1 == str2); // FALSCHDie neue Methode besteht darin, verschiedene Objekte zu generieren. Erzeugen nacheinander.
In der zweiten Art und Weise werden mehrere "ABC" -Schaiten erstellt, und es gibt nur ein Objekt im Speicher. Diese Schreibmethode ist vorteilhaft und spart Speicherplatz. Gleichzeitig kann es die Laufgeschwindigkeit des Programms bis zu einem gewissen Grad verbessern, da die JVM automatisch entscheidet, ob es erforderlich ist, ein neues Objekt basierend auf der tatsächlichen Situation der Daten im Stapel zu erstellen. Für den Code von String Str = New String ("ABC");
HINWEIS: HINWEIS: Wenn wir eine Klasse unter Verwendung eines Formats wie String Str = "ABC" definieren, halten wir es immer als selbstverständlich an, dass wir ein Objekt STR der String -Klasse erstellen. Sorgen Sie sich um die Falle! Das Objekt wurde möglicherweise nicht erstellt! Und vielleicht nur auf ein Objekt verweisen, das zuvor erstellt wurde. Nur durch die neue () -Methode kann wir sicherstellen, dass jedes Mal ein neues Objekt erstellt wird.
Mehrere Beispiele für das Problem mit konstantem Pooling -Problem
Beispiel 1:
Java -Code
String S0 = "Kvill"; String S1 = "Kvill"; String S2 = "KV" + "Ill"; System.out.println (S0 == S1); System.out.println (S0 == S2); Das Ergebnis ist: TrueTREE
Analyse: Zunächst müssen wir wissen, dass das Ergebnis ist, dass Java sicherstellt, dass eine String -Konstante nur eine Kopie hat.
Da S0 und S1 im Beispiel beide String -Konstanten sind, werden sie während der Zusammenstellungsperiode bestimmt, so dass S0 == S1 wahr ist; Und "KV" und "Ill" sind auch Streichkonstanten. Wenn eine Zeichenfolge durch mehrere String -Konstanten verbunden ist, ist sie definitiv eine String -Konstante selbst, sodass S2 während der Kompilierungsperiode auch in eine Stringkonstante analysiert wird, sodass S2 auch im konstanten Pool ein Hinweis auf "Kvill" ist. Also bekommen wir S0 == S1 == S2;
Beispiel 2:
Beispiel:
Java -Code
Analyse: Die mit neuen String () erstellten Zeichenfolgen sind keine Konstanten und können während der Kompilierungsperiode nicht bestimmt werden, sodass die von New String () erstellten Zeichenfolgen nicht im konstanten Pool platziert werden, sondern ihren eigenen Adressraum.
S0 ist auch eine Anwendung von "Kvill" im konstanten Pool. S1 kann während der Kompilierungsperiode nicht bestimmt werden, daher ist es ein Hinweis auf das neue Objekt "Kvill" zur Laufzeit. S2 kann während der Kompilierungsperiode nicht ermittelt werden, da es die zweite Hälfte der neuen String ("Ill") hat, sodass es auch eine Anwendung des neu erstellten Objekts "Kvill" ist. Wenn Sie diese verstehen, werden Sie wissen, warum dieses Ergebnis erzielt wird.
Beispiel 3:
Java -Code
String a = "a1"; String b = "a" + 1; System.out.println ((a == b)); // result = true string a = "true"; string b = "a" + "true"; System.out.println ((a == b)); // result = true string a = "a3.4"; Zeichenfolge b = "a" + 3.4; System.out.println ((a == b)); // result = true
Analyse: Für die JVM -Verbindung von String -Konstanten optimiert der JVM die "+" -Beendung der konstanten Zeichenfolge nach der Programmkompilierungsperiode. Nehmen Sie als Beispiel "A" + 1. Nach der Optimierung durch den Compiler ist es bereits A1 in der Klasse. Während der Kompilierungsperiode wird der Wert der String -Konstante bestimmt, sodass das Endergebnis des obigen Programms wahr ist.
Beispiel 4:
Java -Code
String a = "ab"; String bb = "b"; String b = "a" + bb; System.out.println ((a == b)); // result = false
Analyse: Für String -Referenzen in JVM kann der referenzierte Wert während der Programmkompilierungsperiode nicht festgelegt werden, da in der Verbindung von Zeichenfolgen eine String -Referenzen enthält, dh "A" + BB kann vom Compiler nicht optimiert werden, und nur dynamisch zuteilt und die vernetzte neue Adresse dem Programm während des Programms während des Programms zuteilt. Daher ist das Ergebnis des obigen Programms falsch.
Beispiel 5:
Java -Code
Zeichenfolge a = "ab"; endgültige Zeichenfolge bb = "b"; String b = "a" + bb; System.out.println ((a == b)); // result = true
Analyse: Der einzige Unterschied zwischen [4] besteht darin, dass die BB -Saite mit endgültiger Modifikation dekoriert ist. Für endgültige modifizierte Variablen wird es als lokale Kopie des konstanten Wertes zur Kompilierungszeit analysiert und in seinem eigenen konstanten Pool gespeichert oder in seinen Bytecode -Stream eingebettet. Zu diesem Zeitpunkt sind die Auswirkungen von "A" + BB und "A" + "B" gleich. Daher ist das Ergebnis des obigen Programms wahr.
Beispiel 6:
Java -Code
Zeichenfolge a = "ab"; endgültige Zeichenfolge bb = getbb (); String b = "a" + bb; System.out.println ((a == b)); // result = falsePrivate static String getbb () {return "b"; }Analyse: Der JVM verweist BB auf Zeichenfolgen und ihr Wert kann während der Zusammenstellungsperiode nicht ermittelt werden. Erst nachdem die Methode während der Programmlaufzeit aufgerufen wurde, sind der Rückgabewert der Methode und "A" dynamisch verbunden und die Adresse wird b zugewiesen. Daher ist das Ergebnis des obigen Programms falsch.
Über String ist unveränderlich
Aus dem obigen Beispiel können wir herausfinden:
String S = "A" + "B" + "C";
Es entspricht String S = "ABC";
Zeichenfolge a = "a";
Zeichenfolge b = "B";
String C = "C";
String S = A + B + C;
Dies ist anders, das Endergebnis entspricht:
Java -Code
StringBuffer temp = new StringBuffer (); temp.Append (a) .Append (b) .Append (c); String s = temp.toString ();
Aus den obigen Analyseergebnissen ist es nicht schwer zu schließen, dass der String den Verbindungsoperator (+) verwendet, um den Grund für die Ineffizienz wie diesen Code zu analysieren:
Java -Code
public class test {public static void main (String args []) {String s = null; für (int i = 0; i <100; i ++) {s+= "a"; }}}Jedes Mal, wenn + erledigt ist, wird ein StringBuilder -Objekt generiert und gilt dann an und wirft es weg. Wenn die Schleife das nächste Mal eintrifft, wird ein StringBuilder -Objekt regeneriert und dann die Zeichenfolge angehängt, und die Schleife wird abgeschlossen, bis sie endet. Wenn wir das StringBuilder -Objekt direkt verwenden, um anzuhängen, können wir N - 1 Zeit speichern, um das Objekt zu erstellen und zu zerstören. Daher wird für Anwendungen, die eine String -Verkettung in einer Schleife erfordern, der Anhangvorgang im Allgemeinen unter Verwendung von StringBuffer- oder StringBulider -Objekten durchgeführt.
Aufgrund der unveränderlichen Natur der Saitenklasse gibt es viel zu sagen. Solange Sie wissen, dass sich die Instanz der String nicht ändert, wenn sie erzeugt wird, zum Beispiel: String Str = "KV"+"Ill"+""+"Ans"; Es gibt 4 Saitenkonstanten. Erstens erzeugen „KV“ und „Ill“ im Gedächtnis „Kvill“, und dann werden „Kvill“ und „“ „Kvill“ und „Kvill Ans“ generiert; und die Adresse dieser Zeichenfolge wird zugewiesen.
Endgültige Nutzung und Verständnis in der Zeichenfolge
Java -Code
Final StringBuffer a = new StringBuffer ("111"); Final StringBuffer B = New StringBuffer ("222"); a = b; // Dieser Satz kompiliert erst, wenn er fertig ist. Finale StringBuffer a = new StringBuffer ("111"); A.Append ("222"); /// Compile, nachdem es fertig istEs ist ersichtlich, dass das endgültige nur für den referenzierten "Wert" (d. H. Speicheradresse) gültig ist. Es erzwingt den Hinweis, nur auf das Objekt zu verweisen, auf das ursprünglich hingewiesen wurde. Durch das Ändern des Zeigs führt ein Kompilierungsfehler. Was die Änderungen des Objekts betrifft, auf das es hinweist, ist das Finale unverantwortlich.
Zusammenfassen
Der Stack wird verwendet, um einige lokale variable Daten des ursprünglichen Datentyps und der Verweise auf Objekte (String, Array, Objekt usw.) zu speichern, speichert jedoch keinen Objektinhalt, speichert jedoch keinen Inhalt des Objekts
Die mit dem neuen Schlüsselwort erstellten Objekte werden im Haufen gespeichert.
Eine Zeichenfolge ist eine spezielle Wrapper -Klasse, und ihre Referenzen werden im Stapel gespeichert, und der Objektinhalt muss gemäß der Erstellungsmethode (konstanter Pool und Haufen) bestimmt werden. Einige werden zur Kompilierungszeit erstellt und im String Constant Pool gespeichert, während andere nur zur Laufzeit erstellt werden. Verwenden Sie das neue Schlüsselwort und im Haufen gespeichert.
In dem obigen Artikel wird kurz über den Unterschied zwischen Java+ Speicherzuweisung und variabler Speicherort übereinstimmt, was ich mit Ihnen teile. Ich hoffe, Sie können Ihnen eine Referenz geben und ich hoffe, Sie können wulin.com mehr unterstützen.