Komprimirani OOP-ovi u JVM-u

1. Pregled

JVM upravlja memorijom umjesto nas. Ovo uklanja teret upravljanja memorijom s programera, pa ne trebamo ručno manipulirati pokazivačima na objekte, što je dokazano dugotrajno i sklono pogreškama.

Ispod poklopca JVM uključuje mnoštvo izvrsnih trikova za optimizaciju postupka upravljanja memorijom. Jedan je trik uporaba Stisnuti pokazivači, što ćemo procijeniti u ovom članku. Prvo, pogledajmo kako JVM predstavlja objekte u vrijeme izvođenja.

2. Predstavljanje izvođenja objekata

HotSpot JVM koristi strukturu podataka tzv ups ili Obični pokazivači na objekte za predstavljanje predmeta. Ovi ups ekvivalentni su izvornim C pokazivačima. The instanceOopsu posebna vrsta up koji predstavlja instance objekta u Javi. Štoviše, JVM također podržava nekolicinu drugih ups koji se čuvaju u izvornom stablu OpenJDK.

Pogledajmo kako se postavlja JVM instanceOops u sjećanju.

2.1. Izgled memorije objekata

Izgled memorije instanceOop je jednostavno: to je samo zaglavlje objekta odmah nakon čega slijedi nula ili više referenci na polja instance.

JVM prikaz zaglavlja objekta sastoji se od:

  • Riječ s jednim znakom služi u mnoge svrhe kao što su Pristrasno zaključavanje, Vrijednosti hasha identiteta, i GC. Nije up, ali iz povijesnih razloga nalazi se u OpenJDK-ima up izvorno stablo. Također, stanje riječi marke sadrži samo a uintptr_t, stoga, njegova veličina varira između 4 i 8 bajtova u 32-bitnoj i 64-bitnoj arhitekturi
  • Jedna, moguće komprimirana, klasova riječ, koji predstavlja pokazivač na metapodatke klase. Prije Jave 7, pokazivali su na Trajna generacija, ali od Jave 8 nadalje pokazuju na Metaprostor
  • 32-bitni jaz kako bi se nametnuo poravnanje objekta To čini izgled hardverski ugodnijim, kao što ćemo vidjeti kasnije

Neposredno nakon zaglavlja, mora postojati nula ili više referenci na polja instance. U ovom slučaju, a riječ je izvorna računalna riječ, dakle 32-bitna na naslijeđenim 32-bitnim strojevima i 64-bitna na modernijim sustavima.

Zaglavlje objekta niza, pored riječi mark i klass, sadrži 32-bitnu riječ koja predstavlja njezinu duljinu.

2.2. Anatomija otpada

Pretpostavimo da ćemo prijeći sa naslijeđene 32-bitne arhitekture na moderniji 64-bitni stroj. U početku možemo očekivati ​​trenutno poboljšanje performansi. Međutim, to nije uvijek slučaj kada je uključen JVM.

Glavni krivac za ovu moguću degradaciju performansi su reference 64-bitnih objekata. 64-bitne reference zauzimaju dvostruko više prostora od 32-bitnih referenci, pa to dovodi do veće potrošnje memorije općenito i češćih GC ciklusa. Što je više vremena posvećeno GC ciklusima, to je manje kriški izvršenja CPU-a za naše aplikacijske niti.

Pa, trebamo li se vratiti i ponovno koristiti te 32-bitne arhitekture? Čak i da je to opcija, ne bismo mogli imati više od 4 GB prostora hrpe u 32-bitnim procesnim prostorima bez malo više posla.

3. Komprimirani OOP-ovi

Kako se ispostavilo, JVM može izbjeći gubljenje memorije komprimiranjem pokazivača na objekt ili Ups, tako da možemo imati najbolje iz oba svijeta: omogućujući više od 4 GB prostora hrpe s 32-bitnim referencama u 64-bitnim strojevima!

3.1. Osnovna optimizacija

Kao što smo vidjeli ranije, JVM dodaje obloge objektima tako da je njihova veličina višestruka od 8 bajtova. S ovim ulošcima, posljednja tri bita ups su uvijek nula. To je zato što brojevi koji su višestruki od 8 uvijek završavaju na 000 u binarnom.

Budući da JVM već zna da su zadnja tri bita uvijek nula, nema smisla pohranjivati ​​te beznačajne nule u hrpu. Umjesto toga, pretpostavlja da su tamo i pohranjuje još 3 značajnija bita koja prethodno nismo mogli uklopiti u 32-bitne bitove. Sada imamo 32-bitnu adresu s 3 pomaknute nule udesno, tako da komprimiramo 35-bitni pokazivač u 32-bitni. To znači da možemo koristiti do 32 GB - 232 + 3 = 235 = 32 GB - prostora hrpe bez korištenja 64-bitnih referenci.

Da bi ova optimizacija uspjela, kada JVM treba pronaći objekt u memoriji pomiče pokazivač ulijevo za 3 bita (u osnovi dodaje te 3-nule natrag do kraja). S druge strane, prilikom učitavanja pokazivača na hrpu, JVM pomiče pokazivač udesno za 3 bita da bi odbacio one prethodno dodane nule. U osnovi, JVM izvodi malo više izračuna kako bi uštedio malo prostora. Srećom, pomicanje bitova je doista trivijalna operacija za većinu CPU-a.

Kako bi se omogućilo up kompresiju, možemo koristiti -XX: + UseCompressedOops zastava za podešavanje. The up kompresija je zadano ponašanje od Jave 7 nadalje kada god je maksimalna veličina hrpe manja od 32 GB. Kada je maksimalna veličina hrpe veća od 32 GB, JVM će automatski isključiti up kompresija. Dakle, korištenjem memorije izvan veličine hrpe od 32 Gb treba upravljati drugačije.

3.2. Više od 32 GB

Također je moguće koristiti komprimirane pokazivače kada su veličine Java hrpe veće od 32 GB. Iako je zadano poravnanje objekta 8 bajtova, ovu vrijednost je moguće konfigurirati pomoću -XX:ObjectAlignmentInBytes zastava za podešavanje. Navedena vrijednost trebala bi biti snaga dva i mora biti u rasponu od 8 i 256.

Sa komprimiranim pokazivačima možemo izračunati najveću moguću veličinu hrpe na sljedeći način:

4 GB * ObjectAlignmentInBytes

Na primjer, kada je poravnanje objekta 16 bajtova, možemo koristiti do 64 GB prostora hrpe sa komprimiranim pokazivačima.

Imajte na umu da se povećanjem vrijednosti poravnanja može povećati i neiskorišteni prostor između objekata. Kao rezultat toga, možda nećemo ostvariti nikakve koristi od komprimiranih pokazivača s velikim veličinama Java gomile.

3.3. Futuristički GC-ovi

ZGC, novi dodatak u Javi 11, bio je eksperimentalni i skalabilni sakupljač smeća s malim kašnjenjem.

Može se nositi s različitim rasponima veličine hrpe, a zadržati GC pauze ispod 10 milisekundi. Budući da ZGC treba koristiti 64-bitne pokazivače u boji, ne podržava komprimirane reference. Dakle, korištenje ultra niskog kašnjenja GC poput ZGC-a mora se izvagati s korištenjem više memorije.

Od Jave 15, ZGC podržava komprimirane pokazivače klase, ali još uvijek nema podršku za komprimirane OOP-ove.

Svi novi GC algoritmi, međutim, neće zamijeniti memoriju zbog niske latencije. Na primjer, Shenandoah GC podržava komprimirane reference, osim što je GC s malim vremenima pauze.

Štoviše, i Shenandoah i ZGC finalizirani su od Jave 15.

4. Zaključak

U ovom smo članku opisali Problem upravljanja memorijom JVM u 64-bitnim arhitekturama. Pogledali smo komprimirani pokazivači i poravnanje predmeta, i vidjeli smo kako JVM može riješiti ove probleme, omogućujući nam upotrebu većih veličina gomile s manje rasipnih pokazivača i minimalno dodatnih izračuna.

Za detaljniju raspravu o komprimiranim referencama, preporučljivo je pogledati još jedan sjajni komad Alekseya Shipilëva. Također, da biste vidjeli kako funkcionira alokacija objekata unutar HotSpot JVM-a, pogledajte članak Memorijski raspored objekata u Javi.


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