logički i logički izgled memorije u JVM-u
1. Pregled
U ovom brzom članku vidjet ćemo koji je otisak a boolean vrijednost u JVM-u u različitim okolnostima.
Prvo ćemo pregledati JVM kako bismo vidjeli veličine predmeta. Tada ćemo razumjeti obrazloženje tih veličina.
2. Postavljanje
Da bismo pregledali raspored memorije objekata u JVM-u, opsežno ćemo koristiti Java Object Layout (JOL). Stoga moramo dodati jol-core ovisnost:
org.openjdk.jol jol-core 0.10
3. Veličine predmeta
Ako tražimo od JOL-a da ispiše detalje o VM-u u smislu Veličine predmeta:
System.out.println (VM.current (). Detalji ());
Kada se omoguće komprimirane reference (zadano ponašanje), vidjet ćemo izlaz:
# Pokretanje 64-bitnog HotSpot VM-a. # Korištenje komprimiranog oop-a s 3-bitnim pomakom. # Upotreba komprimiranog klasa s 3-bitnim pomakom. # Objekti su poravnati 8 bajtova. # Veličine polja prema vrsti: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bajtova] # Veličine elemenata niza: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bajtova ]
U prvih nekoliko redaka možemo vidjeti neke opće informacije o VM-u. Nakon toga saznajemo o veličinama predmeta:
- Java reference troše 4 bajta, booleans /bajts su 1 bajt, ugljens /krataks su 2 bajta, ints /plutatis su 4 bajta, i konačno, dugos /dvostrukos su 8 bajtova
- Ove vrste troše jednaku količinu memorije čak i kad ih koristimo kao elemente niza
Dakle, u prisutnosti komprimiranih referenci, svaka boolean vrijednost uzima 1 bajt. Slično tome, svaki boolean u logička [] troši 1 bajt. Međutim, podloge za poravnanje i zaglavlja objekata mogu povećati prostor koji zauzima boolean i logička [] kao što ćemo vidjeti kasnije.
3.1. Nema komprimiranih referenci
Čak i ako onemogućimo komprimirane reference putem -XX: -UseCompressedOops, logička veličina se uopće neće promijeniti:
# Veličine polja prema tipu: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bajtova] # Veličine elemenata niza: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bajtova ]
S druge strane, Java reference uzimaju dvostruko više memorije.
Dakle, unatoč onome što bismo mogli očekivati u početku, booleovi troše 1 bajt umjesto samo 1 bit.
3.2. Razdiranje riječi
U većini arhitektura ne postoji način da se jednom bitu pristupi atomskim putem. Čak i da to želimo učiniti, vjerojatno bismo na kraju zapisivali u susjedne bitove dok bismo ažurirali još jedan.
Jedan od dizajnerskih ciljeva JVM-a je spriječiti ovaj fenomen, poznat kao kidanje riječi. Odnosno, u JVM-u bi svako polje i element polja trebali biti različiti; ažuriranja jednog polja ili elementa ne smiju komunicirati s čitanjima ili ažuriranjima bilo kojeg drugog polja ili elementa.
Da rezimiramo, glavni su razlozi problemi s adresiranjem i kidanje riječi booleans više od samo jednog bita.
4. Obični pokazivači na objekte (OOP)
Sad kad znamo booleans su 1 bajt, razmotrimo ovu jednostavnu klasu:
klasa BooleanWrapper {privatna logička vrijednost; }
Ako pregledamo raspored memorije ove klase pomoću JOL-a:
System.out.println (ClassLayout.parseClass (BooleanWrapper.class) .toPrintable ());
Tada će JOL ispisati izgled memorije:
VRIJEDNOST ZAMJENE VELIČINE OPIS VRIJEDNOST 0 12 (zaglavlje objekta) N / A 12 1 boolean BooleanWrapper.value N / A 13 3 (gubitak zbog sljedećeg poravnanja objekta) Veličina instance: 16 bajta Prostorni gubici: 0 bajta unutarnjih + 3 bajta eksternih = Ukupno 3 bajta
The BooleanWrapper izgled se sastoji od:
- 12 bajtova za zaglavlje, uključujući dva ocjena riječi i jedan klasa riječ. HotSpot JVM koristi ocjena riječ za pohranu GC metapodataka, hashcode identiteta i podataka o zaključavanju. Također, koristi klasa riječ za pohranu metapodataka klase kao što su provjere vremena izvođenja
- 1 bajt za stvarni boolean vrijednost
- 3 bajta popunjavanja radi poravnanja
Prema zadanim postavkama, reference objekta trebaju biti poravnate za 8 bajtova. Stoga JVM dodaje 3 bajta na 13 bajta zaglavlja i boolean kako bi bio 16 bajtova.
Stoga, boolean polja mogu potrošiti više memorije zbog njihovog poravnanja polja.
4.1. Prilagođeno poravnanje
Ako promijenimo vrijednost poravnanja na 32 putem -XX: ObjectAlignmentInBytes = 32, tada se isti izgled klase mijenja u:
VRIJEDNOST ZAMJENE VELIČINE OPIS VRIJEDNOST 0 12 (zaglavlje objekta) N / A 12 1 boolean BooleanWrapper.value N / A 13 19 (gubitak zbog sljedećeg poravnanja objekta) Veličina instance: 32 bajta Prostorni gubici: 0 bajta unutarnjih + 19 bajtova eksternih = Ukupno 19 bajtova
Kao što je gore prikazano, JVM dodaje 19 bajtova popunjavanja kako bi se veličina objekta umnožila na 32.
5. OOP-ovi niza
Pogledajmo kako JVM postavlja a boolean niz u memoriji:
boolean [] vrijednost = novo boolean [3]; System.out.println (ClassLayout.parseInstance (vrijednost) .toPrintable ());
Ovo će ispisati izgled instance na sljedeći način:
OFFSET VELIČINA OPIS 0 4 (zaglavlje objekta) # riječ oznake 4 4 (zaglavlje objekta) # oznaka riječi 8 4 (zaglavlje objekta) # klasa riječ 12 4 (zaglavlje objekta) # dužina polja 16 3 logička vrijednost [Z. # [Z znači logički niz 19 5 (gubitak zbog sljedećeg poravnanja objekta)
Pored dvije ocjena riječi i jedan klasa riječ, pokazivači na niz sadrže dodatnih 4 bajta za pohranu njihove duljine.
Budući da naš niz ima tri elementa, veličina elemenata niza je 3 bajta. Međutim, ova 3 bajta bit će dodana s 5 bajtova za poravnanje polja kako bi se osiguralo pravilno poravnanje.
Iako svaki boolean element u nizu je samo 1 bajt, cijeli niz troši puno više memorije. Drugim riječima, trebali bismo uzeti u obzir zaglavlje i popunjavanje iznad glave prilikom izračunavanja veličine polja.
6. Zaključak
U ovom brzom vodiču vidjeli smo to boolean polja troše 1 bajt. Također, naučili smo da bismo trebali uzeti u obzir općenite troškove zaglavlja i popunjavanja u veličinama predmeta.
Za detaljniju raspravu, toplo se preporučuje provjeriti oops odjeljak izvornog koda JVM-a. Također, Aleksey Shipilëv ima mnogo detaljniji članak o ovom području.
Kao i obično, svi su primjeri dostupni na GitHubu.