Gde se zapravo nalaze objekti kreirani u Javi? U mladoj ili staroj generaciji?
Nakon prethodnih poglavlja, verovatno već znate da se Java objekti kreiraju u heap-u, ali se heap deli na mladu i staru generaciju, a mlada generacija se dalje deli na Eden, From Survivor i To Survivor. Gde se zapravo nalaze objekti koje kreiramo?

O ovome smo već govorili kada smo obrađivali mehanizam sakupljanja smeća, ali bez detalja, a sada ćemo to detaljno objasniti.
Objekti se prvo dodeljuju u Eden oblasti
Heap se deli na mladu i staru generaciju: mlada generacija služi za smeštanje objekata koji se odmah po upotrebi recikliraju (kratkog veka), dok stara generacija služi za smeštanje objekata sa dužim životnim ciklusom.
Većina objekata koje kreiramo spada u objekte kratkog veka, pa će se nalaziti u mladoj generaciji. Mlada generacija se dalje deli na Eden, From Survivor i To Survivor, a naši kreirani objekti će se prvo dodeljivati u Eden oblasti, kao što je prikazano na slici.

Kako se objekti neprestano kreiraju, preostali memorijski prostor u Eden-u će biti sve manji, što će zatim pokrenuti Minor GC, pa će JVM prebaciti objekte koji su preživeli iz Eden oblasti u From Survivor prostor.

Nakon Minor GC-a, novo kreirani objekti će se nastaviti dodeljivati u Eden oblast.

Dakle, kako se kreiraju novi objekti, preostali memorijski prostor u Eden-u će ponovo postajati sve manji i ponovo će se pokrenuti Minor GC. Tada će JVM proceniti preživele objekte u Eden oblasti i From Survivor oblasti, a preživele objekte prebaciti u To Survivor oblast.

Pri sledećem Minor GC-u, preživeli objekti će ponovo preći iz To u From, tako da će uvek jedna Survivor oblast biti prazna, a druga bez fragmentacije.
Veliki objekti odmah ulaze u staru generaciju
Za gorenavedeni proces postoje izuzeci — ako je objekat veoma velik i stalno se kopira napred-nazad u Survivor prostoru, to bi ozbiljno trošilo performanse, pa takvi veliki objekti odmah ulaze u staru generaciju.

Cilj ove strategije je smanjenje režije kopiranja tokom sakupljanja smeća, jer je kopiranje velikih objekata vremenski zahtevnije nego kopiranje malih.
Parametrom -XX:PretenureSizeThreshold može se postaviti prag iznad kojeg će veliki objekti biti direktno dodeljeni staroj generaciji. Ako veličina objekta premašuje ovaj prag, biće direktno dodeljen staroj generaciji. Na primer, ako želite da postavite prag na 1MB (1024KB), možete to uraditi ovako:
-XX:PretenureSizeThreshold=1048576Dugovečni objekti će preći u staru generaciju
Svaki put kada objekat pređe iz jedne Survivor oblasti u drugu, njegova starost se povećava. Kada starost objekta dostigne određeni prag (podrazumevano 15), biće prebačen u staru generaciju.
Za postavljanje starosnog praga može se koristiti -XX:PretenureSizeThreshold=10.
Da bi virtuelna mašina izračunala koliko je Minor GC-a objekat preživeo, za svaki objekat se definiše brojač starosti objekta. Ako objekat preživi prvi Minor GC u Eden-u, prebačen je u Survivor prostor i njegova starost se povećava za 1; u Survivor oblasti se njegova starost pri svakom preživelom Minor GC-u ponovo povećava za 1. Kada starost dostigne 15, objekat prelazi u staru generaciju.

Dinamička procena starosti
Pored dostizanja starosnog praga MaxTenuringThreshold, postoji još jedan način za prelazak u staru generaciju, a to je dinamička procena starosti: JVM će proveriti veličinu objekata u svakoj starosnoj grupi i proceniti njihovu ukupnu zapreminu u Survivor prostoru. JVM će odabrati najmanju starost takvu da objekti te i veće starosti mogu popuniti deo Survivor prostora (obično manje od polovine ukupnog prostora), a zatim te objekte unaprediti u staru generaciju.
Na primer, ako je Survivor 100MB, Hello1 i Hello2 su stari po 3 godine, a njihov zbir prelazi 50MB, a Hello3 je star 4 godine — u tom slučaju sva tri objekta prelaze u staru generaciju.

Garantovanje prostora za dodelu
Gore je pomenuto da će preživeli objekti biti smešteni u drugi Survivor prostor, ali šta ako su ti preživeli objekti veći od Survivor prostora?
Ceo proces je sledeći:
- Pre Minor GC-a, JVM prvo proverava da li je maksimalni neprekidni raspoloživi prostor u staroj generaciji veći od ukupnog prostora svih objekata u mladoj generaciji; ako jeste, pokreće Minor GC.
- Ako nije, proverava se da li je postavljen HandlePromotionFailure; ako nije postavljen, pokreće se Full GC.
- Ako je HandlePromotionFailure postavljen, proverava se da li je maksimalni neprekidni raspoloživi prostor u staroj generaciji veći od prosečne veličine objekata koji su prethodno unapređivani u staru generaciju; ako je manji, pokreće se Full GC.
- Ako je veći, pokreće se Minor GC. Nakon Minor GC-a proverava se da li Survivor prostor može da primi preživele objekte; ako ne može, smeštaju se u staru generaciju, a ako može, smeštaju se direktno u Survivor prostor. Ako ni stara generacija ne može da primi preživele objekte, dolazi do neuspeha garantovanja (Handle Promotion Failure) i pokreće se Full GC.

Uloga HandlePromotionFailure: kada je postavljen na true (podrazumevana vrednost), JVM će pokušati da nastavi sa Minor GC čak i kada stara generacija nema dovoljno prostora za sve objekte koji treba da budu unapređeni. JVM će pokušati da oslobodi više prostora u staroj generaciji ili da preduzme druge mere za suočavanje sa nedostatkom prostora. Time se izbegava prevremeno pokretanje Full GC-a (sakupljanja celog heap-a) zbog nedostatka prostora u staroj generaciji. Full GC je obično znatno vremenski zahtevniji od Minor GC-a i dovodi do dužih pauza.
Stek i oblast metoda
Objekti kreirani u Javi gotovo uvek se nalaze u heap-u, što uključuje objekte i nizove kreirane pomoću ključne reči new.
Reference na objekte obično se nalaze u steku — na primer, kada u metodi deklarišete promenljivu MyClass obj = new MyClass();, promenljiva obj (referenca koja ukazuje na objekat u heap-u) se čuva na steku.
Oblast metoda služi za skladištenje informacija o klasama koje je učitao JVM, konstanti, statičkih promenljivih i koda koji je kompajlirao just-in-time kompajler.
U Javi 8, trajna generacija (Permanent Generation) zamenjena je metaprostorom (Metaspace). Metaprostor koristi lokalnu memoriju (memoriju operativnog sistema), a ne JVM memoriju.
Rezime
U ovom članku smo uglavnom obradili:
- Objekti kreirani u Javi se prvo dodeljuju u Eden oblasti.
- Veliki objekti odmah ulaze u staru generaciju.
- Dugovečni objekti prelaze u staru generaciju.
- Dinamička procena starosti.
- Garantovanje prostora za dodelu.
Ovo predstavlja dopunu za premeštanje objekata iz mehanizma sakupljanja smeća o kojem smo ranije govorili. Razumevanje ovih memorijskih oblasti je važno za razumevanje upravljanja memorijom u Javi i optimizaciju performansi programa.
