Ich kenne das Konzept eines Konstantenpools und des String-Konstantenpools, die von JVMs zum Behandeln von String-Literalen verwendet werden. Ich weiß jedoch nicht, welcher Speichertyp von der JVM zum Speichern von konstanten String-Literalen verwendet wird. Der Stapel oder der Haufen? Da es sich um ein Literal handelt, das keiner Instanz zugeordnet ist, würde ich davon ausgehen, dass es im Stapel gespeichert wird. Aber wenn es von keiner Instanz referenziert wird, muss das Literal durch GC-Lauf gesammelt werden (korrigieren Sie mich, wenn ich falsch liege). Wie wird das gehandhabt, wenn es im Stapel gespeichert ist?
103
Antworten:
Die Antwort ist technisch weder. Gemäß der Java Virtual Machine-Spezifikation befindet sich der Bereich zum Speichern von Zeichenfolgenliteralen im Laufzeitkonstantenpool . Der Speicherbereich des Laufzeitkonstantenpools wird pro Klasse oder pro Schnittstelle zugewiesen, sodass er überhaupt nicht an Objektinstanzen gebunden ist. Der Laufzeitkonstantenpool ist eine Teilmenge des Methodenbereichs, in dem "Strukturen pro Klasse wie der Laufzeitkonstantenpool, Feld- und Methodendaten sowie der Code für Methoden und Konstruktoren gespeichert werden, einschließlich der speziellen Methoden, die bei der Klassen- und Instanzinitialisierung und -schnittstelle verwendet werden Typinitialisierung ". Die VM-Spezifikation besagt, dass zwar der Methodenbereich ist logisch Teil des Heaps und schreibt nicht vor, dass der im Methodenbereich zugewiesene Speicher einer Speicherbereinigung oder anderen Verhaltensweisen unterliegt, die mit normalen Datenstrukturen verbunden wären, die dem Heap zugewiesen sind.
quelle
Wie in dieser Antwort erläutert , ist der genaue Speicherort des Zeichenfolgenpools nicht angegeben und kann von JVM-Implementierung zu JVM-Implementierung variieren.
Es ist interessant festzustellen, dass sich der Pool bis Java 7 im Permgen-Bereich des Heaps auf der Hotspot-JVM befand, aber seit Java 7 in den Hauptteil des Heaps verschoben wurde :
In Java 8 Hotspot wurde die permanente Generierung vollständig entfernt.
quelle
String-Literale werden nicht im Stapel gespeichert. Noch nie. Tatsächlich werden keine Objekte auf dem Stapel gespeichert.
Stringliterale (oder genauer gesagt, die String - Objekte , die sie vertreten)
sindhistorisch in einem Heap gespeichert wurden genannt die „PermGen“ Haufen. (Permgen steht für permanente Erzeugung.)Unter normalen Umständen sind String-Literale und viele andere Dinge im Permgen-Heap "permanent" erreichbar und werden nicht durch Müll gesammelt. (Beispielsweise sind String-Literale immer über die Codeobjekte erreichbar, die sie verwenden.) Sie können jedoch eine JVM so konfigurieren, dass versucht wird, dynamisch geladene Klassen zu finden und zu sammeln, die nicht mehr benötigt werden. Dies kann dazu führen, dass String-Literale durch Müll gesammelt werden .
ERKLÄRUNG 1 - Ich sage nicht, dass Permgen nicht GC'ed wird. Dies ist normalerweise der Fall, wenn die JVM beschließt, einen vollständigen GC auszuführen. Mein Punkt ist, dass String- Literale erreichbar sind, solange der Code, der sie verwendet, erreichbar ist, und der Code erreichbar ist, solange der Klassenlader des Codes erreichbar ist, und für die Standard-Klassenlader bedeutet dies "für immer".
CLARIFICATION # 2 - Tatsächlich verwendet Java 7 und höher den regulären Heap, um den Zeichenfolgenpool zu speichern. Daher befinden sich String-Objekte, die String-Literale und interne Zeichenfolgen darstellen, tatsächlich im regulären Heap. (Einzelheiten finden Sie in der Antwort von @ assylias.)
Es gibt keine "dünne Linie". Es ist wirklich sehr einfach:
String
Objekte, die Zeichenfolgenliterale darstellen / diesen entsprechen, werden im Zeichenfolgenpool gespeichert.String
Objekte, die durch einenString::intern
Aufruf erstellt wurden , werden im Zeichenfolgenpool gespeichert.String
Objekte werden NICHT im String-Pool gespeichert.Dann gibt es die separate Frage, wo der String-Pool "gespeichert" ist. Vor Java 7 war es der Permgen-Heap. Ab Java 7 ist es der Haupthaufen.
quelle
String-Pooling
String.intern () in Java 6
String.intern () in Java 7
String-Pool-Werte werden durch Müll gesammelt
Quelle.
quelle
Wie andere Antworten erklären, ist der Speicher in Java in zwei Teile unterteilt
1. Stapel: Pro Thread wird ein Stapel erstellt, in dem Stapelrahmen gespeichert werden, in denen wiederum lokale Variablen gespeichert werden. Wenn eine Variable ein Referenztyp ist, verweist diese Variable auf einen Speicherort im Heap für das tatsächliche Objekt.
2. Heap: Alle Arten von Objekten werden nur im Heap erstellt.
Der Heap-Speicher ist wieder in 3 Teile unterteilt
1. Junge Generation: Speichert Objekte mit kurzer Lebensdauer. Die junge Generation selbst kann in zwei Kategorien unterteilt werden: Eden Space und Survivor Space .
2. Alte Generation: Speichern Sie Objekte, die viele Speicherbereinigungszyklen überstanden haben und auf die noch verwiesen wird.
3. Permanente Generierung: Speichert Metadaten über das Programm, z. B. den Laufzeitkonstantenpool.
Der String-Konstantenpool gehört zum permanenten Generierungsbereich des Heap-Speichers.
Wir können den Laufzeitkonstantenpool für unseren Code im Bytecode sehen, indem
javap -verbose class_name
wir Methodenreferenzen (#Methodref), Klassenobjekte (#Class), Zeichenfolgenliterale (#String) anzeigen.Sie können mehr darüber auf meinen Artikel lesen Wie funktioniert JVM Handle Methode Overloading und Übergeordnete Intern .
quelle
Zu den großartigen Antworten, die hier bereits enthalten sind, möchte ich etwas hinzufügen, das in meiner Perspektive fehlt - eine Illustration.
Wie Sie bereits teilen, teilt JVM den zugewiesenen Speicher eines Java-Programms in zwei Teile. einer ist Stapel und ein anderer ist Haufen . Der Stapel wird für Ausführungszwecke und der Heap für Speicherzwecke verwendet. In diesem Heapspeicher weist JVM Speicher zu, der speziell für Zeichenfolgenliterale vorgesehen ist. Dieser Teil des Heapspeichers wird als String-Konstanten-Pool bezeichnet .
Wenn Sie beispielsweise die folgenden Objekte initiieren:
String-Literale
s1
unds2
gehen zum String-Konstanten-Pool, Objekte obj1, obj2, obj3 zum Heap. Alle von ihnen werden aus dem Stapel referenziert.Beachten Sie außerdem, dass "abc" im Heap- und im String-Konstantenpool angezeigt wird. Warum wird
String s1 = "abc"
undString obj1 = new String("abc")
wird so geschaffen? Dies liegt daran, dassString obj1 = new String("abc")
explizit eine neue und referenziell unterschiedliche Instanz eines String-Objekts erstellt wird undString s1 = "abc"
möglicherweise eine Instanz aus dem String-Konstantenpool wiederverwendet wird, sofern eine verfügbar ist. Für eine ausführlichere Erklärung: https://stackoverflow.com/a/3298542/2811258quelle