boolean a boolean Rozloženie pamäte v JVM
1. Prehľad
V tomto rýchlom článku sa pozrieme, čo je to stopa a boolovský hodnotu v JVM za rôznych okolností.
Najskôr skontrolujeme JVM, aby sme videli veľkosti objektov. Potom pochopíme dôvody týchto veľkostí.
2. Inštalácia
Na kontrolu rozloženia pamäte objektov v JVM budeme vo veľkom rozsahu používať Java Object Layout (JOL). Preto musíme pridať veselé jadro závislosť:
org.openjdk.jol jol-core 0,10
3. Veľkosti predmetov
Ak požiadame JOL o vytlačenie podrobností VM z hľadiska veľkostí objektov:
System.out.println (VM.current (). Details ());
Keď sú komprimované odkazy povolené (predvolené správanie), zobrazí sa nám výstup:
# Spustenie 64-bitového HotSpot VM. # Používanie komprimovaného OOP s 3-bitovým posunom. # Používanie komprimovaného klassu s 3-bitovým posunom. # Objekty sú zarovnané na 8 bajtov. # Veľkosti polí podľa typu: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bajty] # Veľkosti prvkov poľa: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bajty ]
V prvých niekoľkých riadkoch vidíme niekoľko všeobecných informácií o VM. Potom sa dozvieme o veľkostiach objektov:
- Referenčné dokumenty Java spotrebujú 4 bajty, boolovskýs /bajts sú 1 bajt, chars /krátkys sú 2 bajty, ints /plaváks sú 4 bajty a nakoniec dlhos /dvojitýs sú 8 bajtov
- Tieto typy spotrebúvajú rovnaké množstvo pamäte, aj keď ich používame ako prvky poľa
Takže za prítomnosti komprimovaných odkazov boolovský hodnota trvá 1 bajt. Podobne každý boolovský v boolean [] spotrebuje 1 bajt. Vyrovnávacie výplne a hlavičky objektov však môžu zväčšiť priestor, ktorý spotrebuje boolovský a boolean [] ako uvidíme neskôr.
3.1. Žiadne komprimované odkazy
Aj keď deaktivujeme komprimované odkazy pomocou -XX: -UseCompressedOops, booleovská veľkosť sa vôbec nezmení:
# Veľkosti polí podľa typu: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bajty] # Veľkosti prvkov poľa: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bajty ]
Na druhej strane, referencie Java zaberajú dvojnásobok pamäte.
Takže napriek tomu, čo by sme najskôr mohli očakávať, booleans spotrebúvajú 1 bajt namiesto iba 1 bitu.
3.2. Roztrhanie slova
Vo väčšine architektúr neexistuje spôsob, ako získať prístup k jedinému bitu atómovo. Aj keby sme to chceli urobiť, pravdepodobne by sme pri aktualizácii iného skončili zápisom na susedné bity.
Jedným z cieľových zámerov JVM je zabrániť tomuto javu, známemu ako trhanie slov. To znamená, že v JVM by mal byť každý prvok poľa a poľa odlišný; aktualizácie jedného poľa alebo prvku nesmú interagovať s čítaním alebo aktualizáciami iného poľa alebo prvku.
Aby sme to zhrnuli, hlavnými dôvodmi sú problémy s adresnosťou a trhaním slov boolovskýsú viac ako iba jeden jediný bit.
4. Ukazovatele bežného objektu (OOP)
Teraz, keď už vieme boolovskýs sú 1 bajt, zvážme túto jednoduchú triedu:
class BooleanWrapper {private boolean value; }
Ak skontrolujeme rozloženie pamäte tejto triedy pomocou JOL:
System.out.println (ClassLayout.parseClass (BooleanWrapper.class) .toPrintable ());
Potom JOL vytlačí rozloženie pamäte:
TYP ZMENY VEĽKOSTI POPIS HODNOTA 0 12 (hlavička objektu) N / A 12 1 boolean BooleanWrapper.value N / A 13 3 (strata v dôsledku ďalšieho zarovnania objektu) Veľkosť inštancie: 16 bajtov Straty priestoru: 0 bajtov interné + 3 bajty externé = 3 bajty spolu
The BooleanWrapper rozloženie pozostáva z:
- 12 bajtov pre hlavičku, vrátane dvoch známka slová a jeden klass slovo. HotSpot JVM používa známka slovo na uloženie metaúdajov GC, hašovacieho kódu identity a informácií o uzamknutí. Používa tiež klass slovo na ukladanie metaúdajov triedy, napríklad kontroly typu za behu
- 1 bajt pre skutočnú hodnotu boolovský hodnotu
- 3 bajty výplne na účely zarovnania
V predvolenom nastavení by odkazy na objekty mali byť zarovnané o 8 bajtov. Preto JVM pridáva 3 bajty k 13 bajtom hlavičky a boolovský aby to bolo 16 bajtov.
Preto boolovský polia môžu kvôli zarovnaniu poľa spotrebovať viac pamäte.
4.1. Vlastné zarovnanie
Ak zmeníme hodnotu zarovnania na 32 pomocou -XX: ObjectAlignmentInBytes = 32, potom sa rovnaké rozloženie triedy zmení na:
TYP ZMENY VEĽKOSTI POPIS HODNOTA 0 12 (hlavička objektu) N / A 12 1 boolean BooleanWrapper.value N / A 13 19 (strata v dôsledku ďalšieho zarovnania objektu) Veľkosť inštancie: 32 bajtov Straty priestoru: 0 bajtov interné + 19 bajtov externé = 19 bajtov spolu
Ako je uvedené vyššie, JVM pridáva 19 bajtov výplne, aby sa veľkosť objektu stala násobkom 32.
5. Pole OOP
Pozrime sa, ako JVM ustanovuje a boolovský pole v pamäti:
boolean [] hodnota = nový boolean [3]; System.out.println (ClassLayout.parseInstance (hodnota) .toPrintable ());
Toto vytlačí rozloženie inštancie nasledovne:
POPIS TYPU VEĽKOSTI POSUNU 0 4 (hlavička objektu) # označiť slovo 4 4 (hlavička objektu) # označiť slovo 8 4 (hlavička objektu) # klass word 12 4 (hlavička objektu) # dĺžka poľa 16 3 boolean [Z. # [Z znamená booleovské pole 19 5 (strata v dôsledku ďalšieho zarovnania objektu)
Okrem dvoch známka slová a jeden klass slovo, ukazovatele poľa obsahujú ďalšie 4 bajty na uloženie ich dĺžok.
Pretože naše pole má tri prvky, veľkosť prvkov poľa je 3 bajty. Avšak tieto 3 bajty budú vyplnené 5 bajtmi zarovnania poľa, aby sa zabezpečilo správne zarovnanie.
Aj keď každý boolovský prvok v poli má iba 1 bajt, celé pole spotrebuje oveľa viac pamäte. Inými slovami, pri výpočte veľkosti poľa by sme mali brať do úvahy hlavičku a výplň.
6. Záver
V tomto rýchlom návode sme to videli boolovský polia spotrebúvajú 1 bajt. Dozvedeli sme sa tiež, že by sme mali brať do úvahy réžiu hlavičky a výplne vo veľkostiach objektov.
Pre podrobnejšiu diskusiu sa dôrazne odporúča skontrolovať sekciu oops zdrojového kódu JVM. Aleksey Shipilëv má v tejto oblasti tiež oveľa podrobnejší článok.
Ako obvykle sú všetky príklady dostupné na GitHub.