Guide til Java String Pool

1. Oversikt

De String objektet er den mest brukte klassen på Java-språket.

I denne raske artikkelen vil vi utforske Java String Pool - det spesielle minneområdet der Strenger lagres av JVM.

2. String Interning

Takket være uforanderligheten til Strenger i Java kan JVM optimalisere mengden minne som tildeles dem av lagrer bare ett eksemplar av hver bokstav String i bassenget. Denne prosessen kalles interning.

Når vi oppretter en String variabel og tilordne en verdi til den, søker JVM i bassenget etter en String av lik verdi.

Hvis funnet, vil Java-kompilatoren ganske enkelt returnere en referanse til minneadressen uten å tildele ekstra minne.

Hvis den ikke blir funnet, blir den lagt til i bassenget (internert) og referansen vil bli returnert.

La oss skrive en liten test for å bekrefte dette:

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

3. Strenger Tildelt ved hjelp av konstruktøren

Når vi oppretter en String via ny operatør, vil Java-kompilatoren opprette et nytt objekt og lagre det i haugplassen som er reservert for JVM.

Hver String opprettet som dette vil peke på en annen minnesregion med sin egen adresse.

La oss se hvordan dette er forskjellig fra forrige tilfelle:

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

4. String Bokstavelig vs. Strengobjekt

Når vi lager en String objektet ved hjelp av ny() operatør, skaper den alltid et nytt objekt i heapminne. På den annen side, hvis vi lager et objekt ved hjelp av String bokstavelig syntaks f.eks. “Baeldung”, den kan returnere et eksisterende objekt fra strengbassenget, hvis det allerede eksisterer. Ellers vil det opprette et nytt strengobjekt og legge i strengbassenget for fremtidig gjenbruk.

På høyt nivå er begge de String gjenstander, men hovedforskjellen kommer fra det punktet ny() operatøren oppretter alltid en ny String gjenstand. Også når vi oppretter en String bruker bokstavelig - det er internert.

Dette vil være mye mer tydelig når vi sammenligner to String objekter opprettet ved hjelp av String bokstavelig og ny operatør:

Streng først = "Baeldung"; String andre = "Baeldung"; System.out.println (første == sekund); // Sant

I dette eksemplet er String objekter vil ha samme referanse.

Deretter la oss lage to forskjellige objekter ved hjelp av ny og sjekk at de har forskjellige referanser:

String tredje = ny streng ("Baeldung"); Streng fjerde = ny streng ("Baeldung"); System.out.println (tredje == fjerde); // Falsk

Tilsvarende når vi sammenligner a String bokstavelig med en String objekt opprettet ved hjelp av ny() bruker == operator, vil den returnere falsk:

String femte = "Baeldung"; String sjette = ny streng ("Baeldung"); System.out.println (femte == sjette); // Falsk

Generelt, vi bør bruke String bokstavelig notasjon når det er mulig. Det er lettere å lese, og det gir kompilatoren en sjanse til å optimalisere koden vår.

5. Manuell interning

Vi kan internere en String i Java String Pool ved å ringe turnuskandidat() metode på objektet vi ønsker å praktisere.

Manuell interning av String vil lagre referansen i bassenget, og JVM vil returnere denne referansen når det er nødvendig.

La oss lage en test case for dette:

String constantString = "internert Baeldung"; Streng newString = ny streng ("internert Baeldung"); assertThat (constantString) .isNotSameAs (newString); Streng internedString = newString.intern (); assertThat (constantString) .isSameAs (internedString);

6. Søppelinnsamling

Før Java 7, JVM plassert Java String Pool i PermGen plass, som har en fast størrelse - den kan ikke utvides ved kjøretid og er ikke kvalifisert for søppeloppsamling.

Risikoen for interning Strenger i PermGen (i stedet for Haug) er det vi kan få en Tomt for minne feil fra JVM hvis vi praktiserer for mange Strenger.

Fra Java 7 og utover er Java String Pool lagret i Haug plass, som er søppeloppsamlet av JVM. Fordelen med denne tilnærmingen er redusert risiko for Tomt for minne feil fordi ikke referert Strenger vil bli fjernet fra bassenget, og frigjør derved minne.

7. Ytelse og optimaliseringer

I Java 6 er den eneste optimaliseringen vi kan utføre å øke PermGen plass under programmet påkallelse med MaxPermSize JVM-alternativ:

-XX: MaxPermSize = 1G

I Java 7 har vi mer detaljerte alternativer for å undersøke og utvide / redusere bassengstørrelsen. La oss se de to alternativene for å se bassengstørrelsen:

-XX: + PrintFlagsFinal
-XX: + PrintStringTableStatistics

Hvis vi ønsker å øke bassengstørrelsen når det gjelder bøtter, kan vi bruke StringTableSize JVM-alternativ:

-XX: StringTableSize = 4901

Før Java 7u40 var standard bassengstørrelse 1009 bøtter, men denne verdien var gjenstand for noen få endringer i nyere Java-versjoner. For å være presis, var standard bassengstørrelse fra Java 7u40 til Java 11 60013, og nå økte den til 65536.

Merk at å øke bassengstørrelsen vil forbruke mer minne, men har fordelen av å redusere tiden det tar å sette inn Strenger inn i bordet.

8. En merknad om Java 9

Inntil Java 8, Strenger var internt representert som en rekke tegn - røye [], kodet inn UTF-16, slik at hvert tegn bruker to byte minne.

Med Java 9 er en ny representasjon gitt, kalt Kompakte strenger. Dette nye formatet velger riktig koding mellom røye [] og byte [] avhengig av det lagrede innholdet.

Siden den nye String representasjon vil bruke UTF-16 koding bare når det er nødvendig, mengden av haug minnet vil være betydelig lavere, noe som igjen fører til mindre Søppelmann overhead på JVM.

9. Konklusjon

I denne guiden viste vi hvordan JVM og Java-kompilatoren optimaliserer minnetildelinger for String objekter via Java String Pool.

Alle kodeeksempler som brukes i artikkelen er tilgjengelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found