Útmutató a Java karakterlánckészlethez

1. Áttekintés

A Húr Az objektum a Java nyelv leggyakrabban használt osztálya.

Ebben a rövid cikkben a Java karakterlánckészletet vizsgáljuk meg - a különleges memória régió, ahol Húrok a JVM tárolja.

2. Vonós internálás

Köszönhetően a Húrok Java-ban a JVM optimalizálni tudja az általuk lefoglalt memória mennyiségét minden literálusból csak egy példányt tárol Húr a medencében. Ezt a folyamatot hívják internáló.

Amikor létrehozunk egy Húr változót és hozzárendel hozzá egy értéket, a JVM a készletben keresi a Húr egyenlő értékű.

Ha megtalálta, a Java fordító egyszerűen visszaad egy hivatkozást a memória címére, anélkül, hogy további memóriát osztana ki.

Ha nem található, hozzáadódik a készlethez (internálva), és referenciáját visszaküldi.

Írjunk egy kis tesztet ennek ellenőrzésére:

String konstansString1 = "Baeldung"; String konstansString2 = "Baeldung"; assertThat (konstansString1) .isSameAs (konstansString2);

3. Húrok Kiosztva a Konstruktor használatával

Amikor létrehozunk egy Húr a új operátor, a Java fordító új objektumot hoz létre, és a JVM számára fenntartott kupacterületen tárolja.

Minden Húr így létrehozva egy másik memóriaterületre mutat, saját címmel.

Lássuk, miben különbözik ez az előző esettől:

String konstansString = "Baeldung"; String newString = új karakterlánc ("Baeldung"); assertThat (konstansString) .isNotSameAs (newString);

4. Húr Szó szerint vs Karakterlánc objektum

Amikor létrehozunk egy Húr objektum a új() operátor, mindig új objektumot hoz létre a kupac memóriában. Másrészt, ha egy objektumot használunk Húr szó szerinti szintaxis pl. „Baeldung”, visszaadhat egy meglévő objektumot a String készletből, ha az már létezik. Ellenkező esetben létrehoz egy új String objektumot, és beteszi a karakterlánc készletbe a későbbi újrafelhasználás céljából.

Magas szinten mindkettő az Húr tárgyakat, de a fő különbség onnan származik, hogy új() operátor mindig létrehoz egy újat Húr tárgy. Továbbá, amikor létrehozunk egy Húr literál használatával - internálják.

Ez sokkal egyértelműbb lesz, ha kettőt hasonlítunk össze Húr használatával létrehozott objektumok Húr szó szerinti és a új operátor:

String first = "Baeldung"; Második karakterlánc = "Baeldung"; System.out.println (első == második); // Igaz

Ebben a példában a Húr az objektumoknak ugyanaz lesz a hivatkozása.

Ezután hozzunk létre két különböző objektumot a használatával új és ellenőrizze, hogy különböző hivatkozások vannak-e:

Harmadik húr = új húr ("Baeldung"); Negyedik húr = új húr ("Baeldung"); System.out.println (harmadik == negyedik); // Hamis

Hasonlóképpen, amikor összehasonlítjuk a Húr szó szerint egy Húr használatával létrehozott objektum új() = = operátor használatával visszatér hamis:

Ötödik húr = "Baeldung"; A hatodik húr = új húr ("Baeldung"); System.out.println (ötödik == hatodik); // Hamis

Általánosságban, használnunk kell a Húr szó szerinti jelölés, ha lehetséges. Könnyebb olvasni, és lehetőséget ad a fordítónak a kódunk optimalizálására.

5. Kézi internálás

Manuálisan internálhatunk a Húr a Java karakterlánckészletben a gyakornok() módszer az objektumon, amelyet internálni akarunk.

A. Manuális internálása Húr tárolja referenciáját a készletben, és a JVM szükség esetén visszaadja ezt a referenciát.

Hozzunk létre egy tesztesetet ehhez:

String constantString = "internált Baeldung"; String newString = új String ("internált Baeldung"); assertThat (konstansString) .isNotSameAs (newString); String internedString = newString.intern (); assertThat (konstansString) .isSameAs (internáltString);

6. Szemétgyűjtés

Java 7 előtt a JVM a Java karakterlánc készletet a PermGen hely, amelynek rögzített mérete van - futás közben nem bővíthető, és nem alkalmas szemétszállításra.

Az internálás kockázata Húrok ban,-ben PermGen (a Halom) az, hogy a kaphatunk egy Elfogyott a memória hiba a JVM-től, ha túl sokat internálunk Húrok.

A Java 7-től kezdődően a Java karakterlánckészlet az tárolja a Halom helyet, ami szemetet gyűjt a JVM által. Ennek a megközelítésnek az előnye az csökkent kockázata Elfogyott a memória hiba mert referálatlan Húrok eltávolításra kerül a készletből, ezáltal felszabadítva a memóriát.

7. Teljesítmény és optimalizálás

A Java 6-ban az egyetlen optimalizálás, amelyet végre tudunk hajtani, a PermGen helyet a programhívás során a MaxPermSize JVM opció:

-XX: MaxPermSize = 1G

A Java 7-ben részletesebb lehetőségeink vannak a medence méretének vizsgálatára és bővítésére / csökkentésére. Nézzük meg a medence méretének megtekintésének két lehetőségét:

-XX: + PrintFlagsFinal
-XX: + PrintStringTableStatistics

Ha növelni akarjuk a medence méretét a vödrök tekintetében, használhatjuk a StringTableSize JVM opció:

-XX: StringTableSize = 4901

A Java 7u40 előtt a készlet alapértelmezett mérete 1009 vödör volt, de ez az érték néhány változáson ment keresztül a legújabb Java verziókban. Pontosabban: az alapértelmezett készlet mérete a Java 7u40-től a Java 11-ig 60013 volt, és most 65536-ra nőtt.

Ne feledje, hogy a készlet méretének növelése több memóriát emészt fel, de előnye, hogy csökkenti a Húrok az asztalba.

8. Megjegyzés a Java 9-ről

Java 8-ig, Húrok belsőleg karakterek tömbjeként képviseltették magukat - char [], kódolva UTF-16, így minden karakter két bájt memóriát használ.

A Java 9 esetén egy új reprezentáció jön létre, az úgynevezett Kompakt húrok. Ez az új formátum kiválasztja a megfelelő kódolást char [] és byte[] a tárolt tartalomtól függően.

Mivel az új Húr képviselet a UTF-16 csak szükség esetén kódolja a mennyiségét halom a memória lényegesen alacsonyabb lesz, ami viszont kevesebbet okoz Szemetes rezsi a JVM.

9. Következtetés

Ebben az útmutatóban megmutattuk, hogyan optimalizálja a JVM és a Java fordító a memóriafoglalásokat Húr objektumok a Java karakterlánckészleten keresztül.

A cikkben használt összes kódminta elérhető a GitHubon.