Duboko razumevanje Java bazena string konstanti
Pre nego što sam završio rečenicu, svečana pesma sa Qingdao osnovne škole doprla je do mojih ušiju, "pe ~ vaj ~ mo ~", i ja sam gotovo nesvesno počeo da pevušim.
Koliko objekata kreira new String("Erge")
"Hajde da krenemo od ove interview teme!"
String s = new String("Erge");"Koliko objekata kreira ovaj red koda?"
"Ne, dva!" Odmah sam porekao Sanmejin odgovor. "Kada se ključna reč new koristi za kreiranje string objekta, Java virtuelna mašina prvo traži u bazenu string konstanti da li postoji string objekat 'Erge'. Ako postoji, neće kreirati objekat 'Erge' u bazenu string konstanti, već će direktno kreirati string objekat 'Erge' u hipu, a zatim vratiti adresu tog objekta 'Erge' u hipu i dodeliti je promenljivoj s."
"Ako ne postoji, prvo kreira string objekat 'Erge' u bazenu string konstanti, a zatim kreira još jedan string objekat 'Erge' u hipu, i na kraju vraća adresu tog string objekta 'Erge' iz hipa i dodeljuje je promenljivoj s."
Da nacrtam dijagram, biće mnogo jasnije.

U Javi, na steku se čuvaju promenljive osnovnih tipova podataka i reference na objekte, dok se sami objekti čuvaju na hipu.
Za ovaj red koda String s = new String("Erge");, on kreira dva objekta: jedan je string objekat "Erge", koji je dodat u bazen string konstanti, a drugi je string objekat "Erge" kreiran kroz konstruktor new String(), koji je raspoređen u hip memoriji. Istovremeno, referentna promenljiva s se čuva na steku i pokazuje na string objekat "Erge" u hip memoriji.
"Zašto prvo kreirati objekat u bazenu string konstanti, a zatim i na hipu? Zar to nije suvišno?"
Odgovorio sam: "Da. Pošto se stringovi koriste izuzetno često, Java virtuelna mašina je, radi poboljšanja performansi i smanjenja memorijskih troškova, izvršila određene optimizacije prilikom kreiranja string objekata — posebno je rezervisala jedan prostor za stringove, odnosno bazen string konstanti."
Uloga bazena string konstanti
Obično koristimo dvostruke navodnike da bismo kreirali string objekat, umesto ključne reči new, kao što je prikazano ispod 👇🏻, i na taj način izbegavamo suvišan rad:
String s = "Sanmei";Kada se izvrši String s = "Sanmei", Java virtuelna mašina prvo traži u bazenu string konstanti da li postoji string objekat "Sanmei". Ako postoji, ne kreira nijedan objekat, već direktno vraća adresu objekta "Sanmei" iz bazena string konstanti i dodeljuje je promenljivoj s; ako ne postoji, kreira objekat "Sanmei" u bazenu string konstanti, zatim vraća njegovu adresu i dodeljuje je promenljivoj s.

Java virtuelna mašina je kreirala string objekat , koji je dodat u bazen string konstanti, dok se referentna promenljiva s čuva na steku i pokazuje na string objekat u bazenu string konstanti. Vidiš, time je jedan korak ušteđen, što je efikasnije nego ranije.
"O, razumem, brate.Sa bazenom string konstanti, mogu da kreiram string objekat direktno pomoću dvostrukih navodnika, bez potrebe da kreiram objekat na hipu preko new, zar ne?"
"Tačno. Način sa new uvek će kreirati objekat, bez obzira na to da li sadržaj stringa već postoji, dok će način sa dvostrukim navodnicima koristiti postojeće objekte u bazenu string konstanti." rekoh.
Pogledajmo sledeći primer:
String s = new String("Erge");
String s1 = new String("Erge");Prema našoj prethodnoj analizi, ova dva reda koda kreiraće tri objekta: jedan u bazenu string konstanti i dva na hipu.
Pogledajmo još jedan primer:
String s = "Sanmei";
String s1 = "Sanmei";Ova dva reda koda kreiraće samo jedan objekat — onaj u bazenu string konstanti. Na taj način se performanse svakako poboljšavaju!
Gde se u memoriji nalazi bazen string konstanti?
Rekoh:
Može se podeliti u tri faze.
Pre Jave 7
Pre Jave 7, bazen string konstanti se nalazio u memorijskom području trajne generacije (Permanent Generation), koje je uglavnom služilo za čuvanje nekih string konstanti (jedne vrste statičkih podataka). Trajna generacija je deo Java hipa (Java Heap) i služi za čuvanje statičkih podataka kao što su informacije o klasama, informacije o metodama i informacije o bazenu konstanti.
Java hip je memorijsko područje u JVM-u koje čuva instance objekata i nizove, što znači da je trajna generacija podpodručje Java hipa.
Drugim rečima, statički podaci uskladišteni u trajnoj generaciji i instance objekata i nizovi uskladišteni na hipu su odvojeni; oni imaju različite životne cikluse i načine dodele.
Međutim, veličina trajne generacije i veličina hipa međusobno utiču jedna na drugu, jer obe koriste JVM hip memoriju, pa su im veličine ograničene veličinom JVM hipa.
Dakle, kada kreiramo string konstantu, ona će biti uskladištena u bazenu string konstanti unutar trajne generacije. Ako kreiramo običan string objekat, on će biti uskladišten na hipu. Ako je sadržaj string objekta string konstanta koja već postoji u bazenu string konstanti, taj objekat će pokazivati na postojeću string konstantu, umesto da ponovo kreira novi string objekat.
Da nacrtam dijagram, to otprilike izgleda ovako.

Java 7
Treba napomenuti da je veličina trajne generacije ograničena i da je prilično teško tačno odrediti koliko prostora trajne generacije jedna aplikacija zahteva. Ako u aplikaciji koristimo veliki broj klasa, metoda, konstanti i drugih statičkih podataka, to može dovesti do nedostatka prostora u trajnoj generaciji. U tom slučaju, JVM će baciti grešku OutOfMemoryError.
Zato je, počevši od Jave 7, kako bi se rešio problem nedostatka prostora u trajnoj generaciji, bazen string konstanti premešten iz trajne generacije na hip. Ova promena je napravljena i radi bolje podrške za karakteristike izvršavanja dinamičkih jezika.
Da nacrtam još jedan dijagram, otprilike izgleda ovako.

Java 8
U Javi 8, trajna generacija (PermGen) je uklonjena i zamenjena meta prostorom (Metaspace). Meta prostor je memorijsko područje na samom računaru, odvojeno od JVM memorijskog područja. Ipak, uloga meta prostora je i dalje ista kao uloga prethodne trajne generacije — služi za čuvanje statičkih podataka kao što su informacije o klasama, informacije o metodama i informacije o bazenu konstanti.
Za razliku od trajne generacije, meta prostor ima neke prednosti, na primer:
- Ne dovodi do greške
OutOfMemoryError, jer se veličina meta prostora može dinamički prilagođavati. - Meta prostor koristi memoriju računara, a ne JVM hip memoriju, čime se izbegava problem fragmentacije hip memorije.
- Sakupljanje smeća u meta prostoru odvojeno je od sakupljanja smeća na hipu, što može sprečiti da aplikacija često pokreće Full GC tokom rada zbog učitavanja i uklanjanja klasa.
Da nacrtam još jedan dijagram radi poređenja, sve će biti jasno.

Trajna generacija, oblast metoda, meta prostor
"Brate, možeš li mi ukratko da objasniš koncepte oblasti metoda, trajne generacije i meta prostora? Pomalo su mi nejasni." reče
"Naravno."
- Oblast metoda (Method Area) je koncept u specifikaciji Java virtuelne mašine, poput interfejsa;
- Trajna generacija je jedna implementacija oblasti metoda u HotSpot virtuelnoj mašini, poput implementacione klase interfejsa;
- U Javi 8, trajna generacija je uklonjena, a zamenio ju je meta prostor, što je još jedna implementacija oblasti metoda, znatno fleksibilnija.
Trajna generacija se nalazi unutar područja podataka tokom izvršavanja, pa je njena veličina ograničena veličinom same Java virtuelne mašine. Zato su se pre Jave 8 često susretali sa izuzetkom java.lang.OutOfMemoryError: PermGen Space — PermGen Space upravo označava oblast metoda; dok se meta prostor nalazi direktno u memoriji računara, pa je ograničen samo dostupnom memorijom računara.
upitah.
"Da, da." odgovori
"O bazenu string konstanti, toliko za sada. Zar nije prilično zanimljivo?" rekoh.
"Jeste, sada sam potpuno razumela bazen string konstanti. Brate, strašan si!" reče
