Kompakt húrok a Java 9-ben

1. Áttekintés

Húrok Java-ban belsőleg a char [] karaktereit tartalmazó Húr. És minden char 2 bájtból áll, mert A Java belsőleg használja az UTF-16-ot.

Például, ha a Húr tartalmaz egy szót angol nyelven, a vezető 8 bit mindegyikére 0 lesz char, mint ASCII karakter egyetlen bájt segítségével ábrázolható.

Sok karakter 16 bitet igényel, hogy képviselje őket, de statisztikailag a legtöbb csak 8 bitet igényel - LATIN-1 karakterábrázolás. Tehát van lehetőség a memóriafelhasználás és a teljesítmény javítására.

Ami szintén fontos, az az Húrs általában a JVM kupacterületének nagy részét foglalják el. És mivel a JVM tárolja őket, a legtöbb esetben a Húr példány kettős lehet tér valójában szüksége van rá.

Ebben a cikkben a JDK6-ban bevezetett Tömörített karakterlánc opcióról és a nemrégiben a JDK9-nel bevezetett új Compact String-ről fogunk beszélni. Mindkettőt a Strings memóriafelhasználásának optimalizálására tervezték a JMV-n.

2. Tömörítve Húr - Java 6

A JDK 6 frissítés 21 Performance Release új virtuális gép-opciót vezetett be:

-XX: + UseCompressedStrings

Ha ez az opció engedélyezve van, Húrok néven tárolják byte[], ahelyett char [] - így sok memóriát spórolhatunk meg. Ezt a lehetőséget azonban végül eltávolították a JDK 7-ből, főleg azért, mert nem kívánt teljesítmény-következményei voltak.

3. Kompakt Húr - Java 9

A Java 9 elhozta a kompakt koncepciót Húrok back.

Ez azt jelenti valahányszor létrehozunk egy Húr ha az összes karakter a Húr ábrázolható bájt - LATIN-1 ábrázolással, egy bájt tömböt használunk belsőleg olyan, hogy egy karakterhez egy bájtot adunk.

Más esetekben, ha valamelyik karakter több mint 8 bitet igényel az ábrázolásához, akkor az összes karakter mindegyikéhez két bájtot tárolunk - UTF-16 ábrázolás.

Tehát alapvetően, amikor csak lehetséges, minden karakterhez csak egy bájtot használ.

Most a kérdés az, hogy - hogyan fog az összes Húr működnek a műveletek? Hogyan különbözteti meg a LATIN-1 és az UTF-16 reprezentációkat?

Nos, ennek a kérdésnek a kezelése érdekében újabb változtatásokat hajtanak végre a program belső megvalósításában Húr. Van egy utolsó mezőnk kódoló, amely megőrzi ezeket az információkat.

3.1. Húr Megvalósítás a Java 9-ben

Eddig a Húr a-ként tárolták char []:

magán végső char [] érték;

Ezentúl ez lesz a byte[]:

privát végső bájt [] értéke;

A változó kódoló:

privát végső bájt kódoló;

Hol a kódoló lehet:

statikus végső bájt LATIN1 = 0; statikus végső bájt UTF16 = 1;

A legtöbb Húr A műveletek most ellenőrzik a kódolót, és elküldik a konkrét megvalósításnak:

public int indexOf (int ch, int fromIndex) {return isLatin1 ()? StringLatin1.indexOf (érték, ch, fromIndex): StringUTF16.indexOf (érték, ch, fromIndex); } privát logikai isLatin1 () {return COMPACT_STRINGS && coder == LATIN1; } 

A JVM-nek minden szükséges információval készen és elérhetően rendelkezésre kell állnia CompactString A virtuális gép opció alapértelmezés szerint engedélyezve van. Letiltásához használhatjuk:

+ XX: -CompactStrings

3.2. Hogyan kódoló Művek

Java 9-ben Húr osztály megvalósítása, a hossza a következőképpen kerül kiszámításra:

public int length () {return value.length >> coder; }

Ha a Húr csak LATIN-1-et tartalmaz, a kódoló 0 lesz, tehát a hossza Húr megegyezik a bájt tömb hosszával.

Más esetekben, ha a Húr értéke UTF-16 reprezentációban van, értéke kódoló 1 lesz, és így a hossza a tényleges bájt tömb felének felel meg.

Vegye figyelembe, hogy a Compact minden módosítása megtörtént Húr, a belső megvalósításban vannak Húr osztályban, és teljesen átláthatóak a fejlesztők számára Húr.

4. Kompakt Húrok vs. Tömörített Húrok

JDK 6 Compressed esetén Húrok, nagy probléma volt, hogy Húr kivitelező csak elfogadott char [] érvként. Ezen kívül sok Húr műveletek függtek char [] ábrázolás és nem bájt tömb. Emiatt sok kibontást kellett elvégezni, ami befolyásolta a teljesítményt.

Míg Compact esetén Húr, az extra mező „kódoló” fenntartása szintén növelheti a rezsit. A költségek csökkentése kódoló és a kicsomagolás bytes to chars (UTF-16 reprezentáció esetén) a módszerek egy része beépített, és a JIT fordító által generált ASM kód is javult.

Ez a változás néhány ellentmondó eredményt hozott. A LATIN-1 indexOf (karakterlánc) belső módszert hív, míg az indexOf (char) nem. Az UTF-16 esetében mindkét módszer intrinsic módszert hív. Ez a kérdés csak a LATIN-1-et érinti Húr és a jövőbeni kiadásokban rögzítik.

Így kompakt Húrok jobbak, mint a Tömörítettek Húrok a teljesítmény szempontjából.

A Compact használatával megtudhatja, hogy mennyi memória van megtakarítva Húrok, elemezték a különféle Java-alkalmazások kupacait. És bár az eredmények nagymértékben függtek a konkrét alkalmazásoktól, az általános fejlesztések szinte mindig jelentősek voltak.

4.1. Különbség a teljesítményben

Lássunk egy nagyon egyszerű példát a Compact engedélyezése és letiltása közötti teljesítménybeli különbségről Húrok:

long startTime = System.currentTimeMillis (); Lista karakterláncok = IntStream.rangeClosed (1, 10_000_000) .mapToObj (Integer :: toString) .collect (toList ()); long totalTime = System.currentTimeMillis () - startTime; System.out.println ("Generated" + stringek.size () + "stringek" + totalTime + "ms." -Ben); startTime = System.currentTimeMillis (); Karakterlánc = = (Karakterlánc) húrok.stream () .limit (100_000) .reduce ("", (l, r) -> l.toString () + r.toString ()); totalTime = System.currentTimeMillis () - startTime; System.out.println ("Létrehozott hosszúsági karaktersorozat" + appended.length () + "a" + totalTime + "ms." -Ban);

Itt 10 milliót hozunk létre Húrs majd naiv módon hozzáfűzi őket. Amikor futtatjuk ezt a kódot (a kompakt karakterláncok alapértelmezés szerint engedélyezve vannak), akkor megkapjuk a kimenetet:

10000000 karakterláncot generált 854 ms alatt. Létrehozta a 488895 hosszúságú karakterláncot 5130 ms alatt.

Hasonlóképpen, ha a Compact karakterláncok letiltásával futtatjuk: -XX: -CompactStrings opció esetén a kimenet:

10000000 karakterláncot generált 936 ms alatt. 488895 hosszúságú húr készült 9727 ms alatt.

Nyilvánvaló, hogy ez egy felületi szintű teszt, és nem lehet nagyon reprezentatív - csupán egy pillanatkép arról, hogy mit tehet az új lehetőség a teljesítmény javítása érdekében ebben a konkrét forgatókönyvben.

5. Következtetés

Ebben az oktatóanyagban a JVM teljesítményének és memóriafelhasználásának optimalizálására tett kísérleteket láttuk tárolással Húrs memória-hatékony módon.

Mint mindig, a teljes kód elérhető a Githubon.