boolsk og boolsk minnelayout i JVM

1. Oversikt

I denne raske artikkelen skal vi se hva som er fotavtrykket til en boolsk verdi i JVM under forskjellige omstendigheter.

Først skal vi inspisere JVM for å se objektstørrelsene. Deretter vil vi forstå begrunnelsen bak disse størrelsene.

2. Oppsett

For å inspisere minneoppsettet til objekter i JVM, skal vi bruke Java Object Layout (JOL) mye. Derfor må vi legge til jol-core avhengighet:

 org.openjdk.jol jol-core 0.10 

3. Objektstørrelser

Hvis vi ber JOL om å skrive ut VM-detaljene når det gjelder objektstørrelser:

System.out.println (VM.current (). Detaljer ());

Når komprimerte referanser er aktivert (standard oppførsel), ser vi utdataene:

# Kjører 64-biters HotSpot VM. # Bruke komprimert oop med 3-bits skift. # Bruke komprimert klass med 3-bits skift. # Objekter er 8 byte justert. # Feltstørrelser etter type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [byte] # Array-elementstørrelser: 4, 1, 1, 2, 2, 4, 4, 8, 8 [byte ]

I de første linjene kan vi se litt generell informasjon om VM. Etter det lærer vi om objektstørrelser:

  • Java-referanser bruker 4 byte, boolsks /bytes er 1 byte, røyes /korts er 2 byte, ints /flytes er 4 byte, og til slutt, langs /dobbelts er 8 byte
  • Disse typene bruker like mye minne selv når vi bruker dem som matriseelementer

Så, i nærvær av komprimerte referanser, hver boolsk verdien tar 1 byte. Tilsvarende hver boolsk i en boolsk [] bruker 1 byte. Imidlertid kan justeringspolstringer og objektoverskrifter øke plassen forbruket av boolsk og boolsk [] som vi får se senere.

3.1. Ingen komprimerte referanser

Selv om vi deaktiverer komprimerte referanser via -XX: -UseCompressedOops, den boolske størrelsen vil ikke endre seg i det hele tatt:

# Feltstørrelser etter type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [byte] # Array-elementstørrelser: 8, 1, 1, 2, 2, 4, 4, 8, 8 [byte ]

På den annen side tar Java-referanser dobbelt så mye minne.

Så til tross for hva vi kunne forvente i begynnelsen, booleanere bruker 1 byte i stedet for bare 1 bit.

3.2. Ordsrivning

I de fleste arkitekturer er det ingen måte å få tilgang til en enkelt bit atomisk. Selv om vi ønsket å gjøre det, ville vi sannsynligvis ende opp med å skrive til tilstøtende biter mens vi oppdaterte en annen.

Et av designmålene til JVM er å forhindre dette fenomenet, kjent som rivende ord. Det vil si at i JVM skal hvert felt og array-element være tydelig; oppdateringer til ett felt eller element må ikke samhandle med lesninger eller oppdateringer av noe annet felt eller element.

For å oppsummere er adresseringsproblemer og ordsriving de viktigste årsakene til at boolsks er mer enn bare en enkeltbit.

4. Ordinære objektpekere (OOP)

Nå som vi vet boolsks er 1 byte, la oss vurdere denne enkle klassen:

klasse BooleanWrapper {privat boolsk verdi; }

Hvis vi inspiserer minneoppsettet til denne klassen ved hjelp av JOL:

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

Deretter vil JOL skrive ut minneoppsettet:

 OFFSET STØRRELSE TYPE BESKRIVELSE VERDI 0 12 (objektoverskrift) Ikke relevant 12 1 boolsk BooleanWrapper.verdi N / A 13 3 (tap på grunn av neste objektjustering) Forekomststørrelse: 16 byte Plasstap: 0 byte internt + 3 byte eksternt = 3 byte totalt

De BooleanWrapper layout består av:

  • 12 byte for overskriften, inkludert to merke ord og ett klass ord. HotSpot JVM bruker merke ord for å lagre GC-metadata, identitetshashkode og låsingsinformasjon. Også bruker den klass ord for å lagre klasse metadata, for eksempel sjekk av kjøretidstype
  • 1 byte for selve boolsk verdi
  • 3 byte polstring for justeringsformål

Objektreferanser skal som standard justeres med 8 byte. Derfor legger JVM til 3 byte til 13 byte med topptekst og boolsk for å gjøre det til 16 byte.

Derfor, boolsk felt kan bruke mer minne på grunn av feltjusteringen.

4.1. Egendefinert justering

Hvis vi endrer justeringsverdien til 32 via -XX: ObjectAlignmentInBytes = 32, så endres samme klasselayout til:

OFFSET STØRRELSE TYPE BESKRIVELSE VERDI 0 12 (objektoverskrift) N / A 12 1 boolsk BooleanWrapper.verdi N / A 13 19 (tap på grunn av neste objektjustering) Forekomststørrelse: 32 byte Romtap: 0 byte internt + 19 byte eksternt = 19 byte totalt

Som vist ovenfor, legger JVM til 19 byte polstring for å gjøre objektstørrelsen til et multiplum av 32.

5. Array OOPs

La oss se hvordan JVM legger ut a boolsk array i minnet:

boolsk [] verdi = ny boolsk [3]; System.out.println (ClassLayout.parseInstance (verdi) .toPrintable ());

Dette vil skrive ut forekomstoppsettet som følger:

OFFSET STØRRELSE TYPE BESKRIVELSE 0 4 (objektoverskrift) # merkeord 4 4 (objektoverskrift) # merkeord 8 4 (objektoverskrift) # klassord 12 4 (objektoverskrift) # arraylengde 16 3 boolsk [Z. # [Z betyr boolsk array 19 5 (tap på grunn av neste objektjustering)

I tillegg til to merke ord og ett klass ord, arraypekere inneholder ytterligere 4 byte for å lagre lengdene.

Siden arrayet vårt har tre elementer, er størrelsen på arrayelementene 3 byte. Derimot, disse 3 bytene vil bli polstret av 5 feltjusteringsbyte for å sikre riktig justering.

Selv om hver boolsk element i en matrise er bare 1 byte, hele matrisen bruker mye mer minne. Med andre ord, vi bør vurdere topptekst og polstring overhead mens vi beregner matrisestørrelsen.

6. Konklusjon

I denne raske opplæringen så vi det boolsk felt bruker 1 byte. Vi lærte også at vi burde vurdere topptekst og polstring i hovedstørrelser.

For en mer detaljert diskusjon anbefales det sterkt å sjekke ut oops-delen av JVM-kildekoden. Aleksey Shipilëv har også en mye mer inngående artikkel på dette området.

Som vanlig er alle eksemplene tilgjengelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found