Sprievodca po Java String Pool

1. Prehľad

The String objekt je najpoužívanejšou triedou v jazyku Java.

V tomto rýchlom článku sa pozrieme na súbor Java String Pool - oblasť špeciálnej pamäte, kde Struny sú uložené JVM.

2. String Interning

Vďaka nemennosti Struny v Jave môže JVM optimalizovať množstvo pamäte, ktorá im bola pridelená uchovávajúc iba jednu kópiu každého literálu String v bazéne. Tento proces sa nazýva interning.

Keď vytvoríme a String premennej a priradí jej hodnotu, JVM vyhľadá v súbore a String rovnakej hodnoty.

Ak sa nájde, kompilátor Java jednoducho vráti odkaz na svoju adresu pamäte bez pridelenia ďalšej pamäte.

Ak sa nenájde, pridá sa do fondu (internovaný) a jeho referencia sa vráti.

Napíšeme malý test, ktorý to overí:

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

3. Struny Pridelené pomocou konštruktéra

Keď vytvoríme a String cez Nový operátor, kompilátor Java vytvorí nový objekt a uloží ho do haldy vyhradenej pre JVM.

Každý String takto vytvorený bude ukazovať na iný pamäťový región s jeho vlastnou adresou.

Pozrime sa, ako sa to líši od predchádzajúceho prípadu:

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

4. String Doslovný vs. Reťazcový objekt

Keď vytvoríme a String objekt pomocou Nový() operátor, vždy vytvorí nový objekt v halde pamäte. Na druhej strane, ak vytvoríme objekt pomocou String doslovna syntax napr. „Baeldung“, môže vrátiť existujúci objekt z bazéna String, ak už existuje. V opačnom prípade vytvorí nový objekt String a vloží sa do fondu reťazcov pre ďalšie použitie v budúcnosti.

Na vysokej úrovni sú obidve String predmety, ale hlavný rozdiel vychádza z bodu, ktorý Nový() operátor vytvorí vždy nový String objekt. Tiež, keď vytvoríme a String pomocou doslovného - je internovaný.

To bude oveľa jasnejšie, keď porovnáme dve String objekty vytvorené pomocou String doslovný a Nový operátor:

Prvý reťazec = "Baeldung"; Druhý reťazec = "Baeldung"; System.out.println (prvý == druhý); // Pravda

V tomto príklade String objekty budú mať rovnaký odkaz.

Ďalej vytvoríme dva rôzne objekty pomocou Nový a skontrolujte, či majú rôzne referencie:

Tretí reťazec = nový reťazec („Baeldung“); Štvrtý reťazec = nový reťazec („Baeldung“); System.out.println (tretí == štvrtý); // Falošné

Podobne, keď porovnáme a String doslovne s a String objekt vytvorený pomocou Nový() operátor pomocou operátora == sa vráti nepravda:

Piaty reťazec = "Baeldung"; Šiesty reťazec = nový reťazec („Baeldung“); System.out.println (piaty == šiesty); // Falošné

Všeobecne, mali by sme použiť String doslovný zápis, ak je to možné. Je ľahšie čitateľný a dáva kompilátoru šancu optimalizovať náš kód.

5. Ručné internovanie

Môžeme ručne internovať a String v Java String Pool zavolaním na stážista () metóda na objekte, ktorý chceme internovať.

Ručné vloženie String uloží svoju referenciu do fondu a JVM ich v prípade potreby vráti.

Vytvorme pre to testovací prípad:

String constantString = "internovaný Baeldung"; String newString = nový String ("internovaný Baeldung"); assertThat (constantString) .isNotSameAs (newString); Reťazec internedString = newString.intern (); assertThat (constantString) .isSameAs (internedString);

6. Zber odpadu

Pred programom Java 7, JVM umiestnil Java String Pool do priečinka PermGen priestor, ktorý má pevnú veľkosť - nedá sa za behu rozšíriť a nie je vhodný na zber odpadu.

Riziko internovania Struny v PermGen (namiesto Halda) je to môžeme dostať Nedostatok pamäte chyba z JVM, ak internujeme príliš veľa Struny.

Od Javy 7 a neskôr je Java String Pool uložené v Halda priestor, v ktorom sa zhromažďujú odpadky JVM. Výhodou tohto prístupu je znížené riziko Nedostatok pamäte chyba pretože neodkazy Struny bude odstránený z fondu, čím sa uvoľní pamäť.

7. Výkon a optimalizácia

V Java 6 je jedinou optimalizáciou, ktorú môžeme vykonať, zvýšenie PermGen priestor počas vyvolania programu pomocou MaxPermSize Možnosť JVM:

-XX: MaxPermSize = 1G

V prostredí Java 7 máme podrobnejšie možnosti na preskúmanie a zväčšenie / zmenšenie veľkosti bazéna. Pozrime sa na dve možnosti zobrazenia veľkosti bazénu:

-XX: + PrintFlagsFinal
-XX: + PrintStringTableStatistics

Ak chceme zvýšiť veľkosť bazéna z hľadiska vedier, môžeme použiť StringTableSize Možnosť JVM:

-XX: StringTableSize = 4901

Pred jazykom Java 7u40 bola predvolená veľkosť fondu 1009 segmentov, ale v novších verziách Java bola táto hodnota predmetom niekoľkých zmien. Presnejšie, predvolená veľkosť fondu od Javy 7u40 do Javy 11 bola 60013 a teraz sa zvýšila na 65536.

Upozorňujeme, že zväčšenie veľkosti fondu bude vyžadovať viac pamäte, ale jeho výhodou je skrátenie času potrebného na vloženie súboru Struny do tabuľky.

8. Poznámka o prostredí Java 9

Až do Java 8, Struny boli interne predstavované ako skupina znakov - char [], zakódované v UTF-16, takže každý znak využíva dva bajty pamäte.

V prostredí Java 9 sa poskytuje nová reprezentácia, tzv Kompaktné struny. Tento nový formát zvolí vhodné kódovanie medzi char [] a byte [] v závislosti od uloženého obsahu.

Od nového String zastúpenie použije UTF-16 kódovanie iba v prípade potreby, množstvo halda pamäť bude výrazne nižšia, čo zase spôsobí menej Smetiar réžia na JVM.

9. Záver

V tejto príručke sme si ukázali, ako JVM a kompilátor Java optimalizujú alokáciu pamäte pre String objekty prostredníctvom fondu Java String Pool.

Všetky ukážky kódu použité v článku sú k dispozícii na GitHub.


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