Gids voor Java String Pool

1. Overzicht

De Draad object is de meest gebruikte klasse in de Java-taal.

In dit korte artikel zullen we de Java String Pool verkennen - het speciale geheugengebied waar Snaren worden opgeslagen door de JVM.

2. String interneren

Dankzij de onveranderlijkheid van Snaren in Java kan de JVM de hoeveelheid geheugen die voor hen wordt toegewezen optimaliseren door slechts één kopie van elke letterlijke opslag Draad in het zwembad. Dit proces heet internering.

Wanneer we een Draad variabele en wijst er een waarde aan toe, zoekt de JVM in de pool naar een Draad van gelijke waarde.

Indien gevonden, zal de Java-compiler eenvoudig een verwijzing naar zijn geheugenadres retourneren, zonder extra geheugen toe te wijzen.

Als het niet wordt gevonden, wordt het toegevoegd aan de pool (geïnterneerd) en wordt de referentie geretourneerd.

Laten we een kleine test schrijven om dit te verifiëren:

String constantString1 = "Baeldung"; String constantString2 = "Baeldung"; assertThat (constantString1) .isSameAs (constantString2);

3. Snaren Toegewezen met behulp van de constructor

Wanneer we een Draad via de nieuw operator, zal de Java-compiler een nieuw object maken en dit opslaan in de heapruimte die is gereserveerd voor de JVM.

Elke Draad op deze manier gemaakt, verwijst naar een ander geheugengebied met een eigen adres.

Laten we eens kijken hoe dit verschilt van het vorige geval:

String constantString = "Baeldung"; String newString = nieuwe String ("Baeldung"); assertThat (constantString) .isNotSameAs (newString);

4. Draad Letterlijk versus String-object

Wanneer we een Draad object met behulp van de nieuw() operator, het maakt altijd een nieuw object in het heap-geheugen. Aan de andere kant, als we een object maken met Draad letterlijke syntaxis b.v. "Baeldung", het kan een bestaand object uit de String-pool retourneren, als het al bestaat. Anders wordt er een nieuw String-object gemaakt en in de stringpool geplaatst voor toekomstig hergebruik.

Op een hoog niveau zijn beide de Draad objecten, maar het belangrijkste verschil komt van het punt dat nieuw() operator maakt altijd een nieuw Draad voorwerp. Ook als we een Draad letterlijk gebruiken - het is geïnterneerd.

Dit wordt veel duidelijker als we er twee vergelijken Draad objecten gemaakt met Draad letterlijk en de nieuw operator:

String first = "Baeldung"; String second = "Baeldung"; System.out.println (eerste == tweede); // Klopt

In dit voorbeeld is de Draad objecten hebben dezelfde referentie.

Laten we vervolgens twee verschillende objecten maken met nieuw en controleer of ze verschillende referenties hebben:

String derde = nieuwe String ("Baeldung"); String vierde = nieuwe String ("Baeldung"); System.out.println (derde == vierde); // Niet waar

Evenzo, wanneer we een Draad letterlijk met een Draad object gemaakt met nieuw() operator met behulp van de == operator, het zal terugkeren vals:

String vijfde = "Baeldung"; String zesde = nieuwe String ("Baeldung"); System.out.println (vijfde == zesde); // Niet waar

Over het algemeen, we zouden de Draad letterlijke notatie indien mogelijk. Het is gemakkelijker te lezen en het geeft de compiler de kans om onze code te optimaliseren.

5. Handmatige internering

We kunnen handmatig een Draad in de Java String Pool door de intern() methode op het object dat we willen stagiair.

Handmatig interneren van het Draad zal zijn referentie in de pool opslaan en de JVM zal deze referentie indien nodig retourneren.

Laten we hiervoor een testcase maken:

String constantString = "geïnterneerde Baeldung"; String newString = nieuwe String ("interned Baeldung"); assertThat (constantString) .isNotSameAs (newString); String internedString = newString.intern (); assertThat (constantString) .isSameAs (internedString);

6. Garbagecollection

Vóór Java 7 was de JVM plaatste de Java String Pool in het PermGen space, die een vaste grootte heeft - deze kan niet tijdens runtime worden uitgebreid en komt niet in aanmerking voor garbage collection.

Het risico van stage lopen Snaren in de PermGen (in plaats van de Hoop) is dat we kunnen een OutOfMemory fout van de JVM als we teveel stage lopen Snaren.

Vanaf Java 7 is de Java String Pool opgeslagen in de Hoop ruimte, dat is vuilnis verzameld door de JVM. Het voordeel van deze aanpak is de verminderd risico op OutOfMemory fout omdat er niet naar wordt verwezen Snaren wordt verwijderd uit het zwembad, waardoor geheugen vrijkomt.

7. Prestaties en optimalisaties

In Java 6 is de enige optimalisatie die we kunnen uitvoeren het verhogen van de PermGen spatie tijdens het aanroepen van het programma met de MaxPermSize JVM-optie:

-XX: MaxPermSize = 1G

In Java 7 hebben we meer gedetailleerde opties om de grootte van het zwembad te onderzoeken en uit te breiden / te verkleinen. Laten we eens kijken naar de twee opties om de grootte van het zwembad te bekijken:

-XX: + PrintFlagsFinal
-XX: + PrintStringTableStatistics

Als we de grootte van het zwembad willen vergroten in termen van emmers, kunnen we de StringTableSize JVM-optie:

-XX: StringTableSize = 4901

Vóór Java 7u40 was de standaard poolgrootte 1009 buckets, maar deze waarde was onderhevig aan enkele wijzigingen in recentere Java-versies. Om precies te zijn, de standaard poolgrootte van Java 7u40 tot Java 11 was 60013 en nu is deze toegenomen tot 65536.

Merk op dat het vergroten van de pool meer geheugen in beslag zal nemen, maar het voordeel heeft dat de tijd die nodig is om het Snaren in de tafel.

8. Een opmerking over Java 9

Tot Java 8, Snaren werden intern weergegeven als een reeks tekens - char [], gecodeerd in UTF-16, zodat elk teken twee bytes geheugen gebruikt.

Met Java 9 wordt een nieuwe weergave geboden, genaamd Compacte snaren. Dit nieuwe formaat zal de juiste codering kiezen tussen char [] en byte[] afhankelijk van de opgeslagen inhoud.

Sinds het nieuwe Draad vertegenwoordiging zal de UTF-16 codering alleen wanneer dat nodig is, de hoeveelheid hoop geheugen zal aanzienlijk lager zijn, wat op zijn beurt minder veroorzaakt Vuilnisman overhead op de JVM.

9. Conclusie

In deze handleiding hebben we laten zien hoe de JVM en de Java-compiler geheugentoewijzingen optimaliseren voor Draad objecten via de Java String Pool.

Alle codevoorbeelden die in het artikel worden gebruikt, zijn beschikbaar op GitHub.