logikai és logikai memória elrendezés a JVM-ben

1. Áttekintés

Ebben a rövid cikkben megnézzük, mi a logikai érték a JVM-ben különböző körülmények között.

Először megvizsgáljuk a JVM-et, hogy megnézzük az objektum méretét. Ezután megértjük a méretek mögött meghúzódó érveket.

2. Beállítás

Az objektumok memóriaelrendezésének ellenőrzéséhez a JVM-ben széles körben fogjuk használni a Java Object Layout (JOL) elemet. Ezért hozzá kell adnunk a jol-core függőség:

 org.openjdk.jol jol-core 0.10 

3. Objektumméretek

Ha arra kérjük a JOL-t, hogy nyomtassa ki a virtuális gép részleteit az objektumméretek szerint:

System.out.println (VM.current (). Részletek ());

Ha a tömörített hivatkozások engedélyezve vannak (az alapértelmezett viselkedés), akkor látni fogjuk a kimenetet:

# 64 bites HotSpot virtuális gép futtatása. # Tömörített opció használata 3 bites váltással. # Tömörített klass használata 3 bites váltással. # Az objektumok 8 bájttal vannak igazítva. # A mezők méretei típus szerint: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bájt] # Tömb elemméretek: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bájt ]

Az első néhány sorban láthatunk néhány általános információt a virtuális gépről. Ezt követően megismerhetjük az objektumméreteket:

  • A Java referenciák 4 bájtot fogyasztanak, logikais /bytes 1 bájt, chars /rövids 2 bájt, ints /úszós 4 bájt, végül hosszús /kettőss 8 bájt
  • Ezek a típusok ugyanannyi memóriát fogyasztanak akkor is, ha tömb elemként használjuk őket

Tehát tömörített referenciák jelenlétében mindegyik logikai az érték 1 bájtot vesz igénybe. Hasonlóképpen mindegyik logikai a logikai [] 1 bájtot fogyaszt. Az igazító párnák és az objektumfejlécek azonban növelhetik az általuk elfogyasztott helyet logikai és logikai [] mint később meglátjuk.

3.1. Nincsenek tömörített hivatkozások

Még akkor is, ha letiltjuk a tömörített hivatkozásokat a -XX: -UseCompressedOops, a logikai méret egyáltalán nem változik:

# A mezők méretei típus szerint: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bájt] # Tömb elemméretek: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bájt ]

Másrészt a Java referenciák kétszer meghaladják a memóriát.

Tehát annak ellenére, amire elsőre számíthatunk, logikai egy bájt helyett 1 bájtot fogyasztanak.

3.2. Szótépés

A legtöbb architektúrában nincs mód atomokhoz egyetlen bit elérésére. Még ha ezt meg is akarjuk tenni, valószínűleg a szomszédos bitekre írunk, miközben frissítünk egy másikat.

A JVM egyik tervezési célja ennek a szószaggatásnak nevezett jelenség megakadályozása. Vagyis a JVM-ben minden mezőnek és tömbelemnek el kell különülnie; Az egyik mező vagy elem frissítései nem léphetnek kapcsolatba más mezők vagy elemek olvasásaival vagy frissítéseivel.

Összefoglalva, a címezhetőség kérdése és a szószakadás a legfőbb ok logikais nem csak egyetlen bit.

4. Közönséges objektummutatók (OOP)

Most, hogy tudjuk logikais 1 bájt, vegyük figyelembe ezt az egyszerű osztályt:

class BooleanWrapper {privát logikai érték; }

Ha megvizsgáljuk ennek az osztálynak a memória elrendezését a JOL segítségével:

System.out.println (ClassLayout.parseClass (BooleanWrapper.class) .toPrintable ());

Ezután a JOL kinyomtatja a memória elrendezését:

 OFFSET MÉRET TÍPUS LEÍRÁS ÉRTÉK 0 12 (objektum fejléc) N / A 12 1 logikai BooleanWrapper.value N / A 13 3 (veszteség a következő objektum igazítás miatt) Példányméret: 16 bájt Helyveszteség: 0 bájt belső + 3 bájt külső = Összesen 3 bájt

A BooleanWrapper elrendezés a következőkből áll:

  • 12 bájt a fejlécért, ebből kettő Mark szavak és egy klass szó. A HotSpot JVM a Mark szó a GC metaadatok, identitás hashcode és zárolási információk tárolására. Ezenkívül használja a klass szó az osztály metaadatainak tárolására, például futásidejű típusú ellenőrzések
  • 1 bájt a tényleges logikai érték
  • 3 bájt párnázás igazítás céljából

Alapértelmezés szerint az objektum hivatkozásokat 8 bájttal kell igazítani. Ezért a JVM 3 bájtot ad hozzá 13 bájt fejléchez és logikai hogy 16 bájt legyen.

Ebből kifolyólag, logikai a mezők több memóriát fogyaszthatnak a mezők igazítása miatt.

4.1. Egyéni igazítás

Ha a beállítási értéket 32-vel módosítjuk -XX: ObjectAlignmentInBytes = 32, akkor ugyanaz az osztálykiosztás a következőre változik:

OFFSET MÉRET TÍPUS LEÍRÁS ÉRTÉK 0 12 (objektum fejléc) N / A 12 1 logikai BooleanWrapper.value N / A 13 19 (veszteség a következő objektum igazítás miatt) Példányméret: 32 bájt Helyveszteség: 0 bájt belső + 19 bájt külső = Összesen 19 bájt

Amint fentebb látható, a JVM 19 bájtnyi kitöltést ad hozzá, hogy az objektum mérete 32-szeres legyen.

5. tömb OOP-k

Lássuk, hogyan írja le a JVM a logikai tömb a memóriában:

logikai [] érték = új logikai [3]; System.out.println (ClassLayout.parseInstance (érték) .toPrintable ());

Ez a következőképpen nyomtatja ki a példány elrendezését:

OFFSET MÉRET TÍPUS LEÍRÁSA 0 4 (objektum fejléc) # jelölőszó 4 4 (objektumfejléc) # jelölőszó 8 4 (objektumfejléc) # klass szó 12 4 (objektumfejléc) # tömbhossz 16 3 logikai [Z. # [Z jelentése logikai tömb 19 5 (veszteség a következő objektum igazítás miatt)

Két mellett Mark szavak és egy klass szó, a tömbmutatók további 4 bájtot tartalmaznak a hosszuk tárolására.

Mivel tömbünknek három eleme van, a tömb elemek mérete 3 bájt. Azonban, ezt a 3 bájtot 5 mező igazítási bájttal töltjük be a megfelelő igazítás érdekében.

Bár mindegyik logikai egy tömb eleme csak 1 bájt, az egész tömb sokkal több memóriát emészt fel. Más szavakkal, a tömb méretének kiszámítása során figyelembe kell vennünk a fejlécet és a párnázási rezsit.

6. Következtetés

Ebben a gyors bemutatóban ezt láttuk logikai a mezők 1 bájtot fogyasztanak. Megtudtuk azt is, hogy a fejlécet és a párnázási költségeket objektumméretben kell figyelembe venni.

Részletesebb megbeszéléshez erősen ajánlott megnézni a JVM forráskód hoppá szakaszát. Aleksey Shipilëvnek sokkal mélyebb cikke van ezen a területen.

Szokás szerint az összes példa elérhető a GitHubon.