Správa paměti v Java
⚡ Chytré shrnutí
Správa paměti v Java vysvětluje, jak JVM rozděluje běhovou paměť mezi Stack, Heap, Codea statické oblasti, jak odkazy na objekty proudí během volání metod a jak Garbage Collector uvolňuje nedostupné objekty, aby aplikace zůstaly stabilní a bez úniků paměti.

Co je zásobníková paměť Java?
Paměť v zásobníku Java je oblast paměti JVM, která ukládá rámce metod, lokální proměnné a referenční proměnné pro každé vlákno. K zásobníku se vždy přistupuje v pořadí „Poslední přišel, první ven“, takže naposledy volaná metoda je nahoře a její lokální proměnné jsou vkládány a odebírány spolu s rámcem.
Každé vlákno v Java Virtuální stroj má svůj vlastní zásobník (stack), který izoluje volání metod a zajišťuje jejich bezpečnost z vláknů (thread-safe). Primitivní lokální hodnoty, jako jsou int, boolean a double, se nacházejí přímo uvnitř rámce, zatímco odkazy na objekty uložené v zásobníku (stack) ukazují na objekty alokované v haldě (heap).
Co je to haldová paměť Java?
Haldová paměť je sdílená oblast JVM, která obsahuje všechny Java objekt a pole vytvořené pomocí operátoru new spolu s veškerými referenčními proměnnými, které patří k těmto objektům jako pole instance. Na rozdíl od zásobníku (Stack) je halda sdílena mezi všemi vlákny, a proto přístup k objektům často vyžaduje synchronizaci.
Halda je oblast, kterou spravuje Garbage Collector. Moderní HotSpot JVM dělí haldu na mladou generaci pro krátkodobé objekty a starou generaci pro dlouhodobé objekty, přičemž metadata tříd jsou uložena v samostatné nativní oblasti zvané Metaspace.
Alokace paměti v Java
Alokace paměti v Java je proces, při kterém JVM během provádění programu vyhradí oblasti virtuální paměti pro proměnné a instance tříd a struktur. Paměť není při deklaraci objektu alokována; pouze se vytvoří odkaz. Vlastní alokace objektu probíhá pomocí operátoru new, takže každý objekt se nachází na haldě (heap).
Jedno Java Alokace paměti je rozdělena do následujících sekcí:
- halda
- Stoh
- Code
- statický
Toto rozdělení paměti je nezbytné pro efektivní správu běhového prostředí.
- Jedno Code sekce obsahuje vaše kompilované byte kód.
- Jedno Stoh sekce obchodů metody, lokální proměnné a referenční proměnné.
- Jedno halda sekce obsahuje Objekty a může také obsahovat referenční proměnné držené jako pole instance.
- Jedno statický sekce drží statická data a statické metody sdíleno napříč všemi instancemi.
Rozdíl mezi místní a instanční proměnnou
Pochopení toho, kde se jednotlivé typy proměnných v JVM nacházejí, pomáhá vysvětlit chování funkcí Stack a Heap. proměnná instance je deklarována uvnitř třídy, ale mimo jakoukoli metodua nachází se na haldě jako součást svého objektu.
class Student{ int num; // num is instance variable public void showData{}
A lokální proměnná je deklarována uvnitř metody, včetně argumentů metodya nachází se na zásobníku uvnitř aktivního rámce.
public void sum(int a){ int x = a + 3; // a, x are local variables }
Rozdíl mezi zásobníkem a haldou
Stack a Heap řeší v JVM různé problémy. Stack poskytuje každému vláknu rychlou, deterministickou alokaci pro krátkodobá data vázaná na rozsah metody, zatímco Heap poskytuje sdílenou oblast pro dlouhodobé objekty, na které se může odkazovat jakékoli vlákno. Krátké video níže shrnuje srovnání před následujícím návodem.
klikněte zde pokud video není přístupné
Abychom viděli, jak Stack a Heap spolupracují, zvažte metodu main, která volá metodu m1.
public void m1{ int x = 20; }
V JVM Stacku je vytvořen rámec pro metodu m1.
Proměnná x v m1 je také vytvořena v rámci pro m1 na zásobníku, jak je znázorněno na obrázku níže.
Metoda m1 poté volá metodu m2. V zásobníku se vytvoří nový rámec pro m2 nad rámec pro m1.
Lokální proměnné b a c jsou také vytvořeny uvnitř rámce pro m2 na zásobníku.
public void m2(int b){ boolean c; }
Dále m2 volá metodu m3. Opět se na vrcholu zásobníku vytvoří rámec pro m3, jak je znázorněno níže.
Řekněme, že metoda m3 vytvoří objekt pro třídu Account, která má dva instance proměnné int p a int q.
class Account { int p; int q; }
Zde je kód pro metodu m3.
public void m3(){ Account ref = new Account(); // more code }
Příkaz new Account() vytvoří objekt Account na haldě.
Referenční proměnná ref se vytvoří na zásobníku uvnitř rámce pro m3.
Operátor přiřazení způsobí, že referenční proměnná ukazuje na objekt na haldě.
Jakmile metoda dokončí provádění, řízení se vrátí volající metodě, kterou je v tomto případě metoda m2.
Rámec pro metodu m3 je vyprázdněn ze zásobníku.
Protože referenční proměnná již neodkazuje na objekt na haldě, stává se tento objekt způsobilým pro garbage collection.
Jakmile metoda m2 skončí, je odstraněna ze zásobníku a všechny její proměnné se stanou nedostupnými. Totéž se stane pro metodu m1 a řízení se nakonec vrátí k hlavní metodě.
Co když objekt obsahuje jinou referenci jako svou instanční proměnnou?
public static void main(String args[]) { A parent = new A(); // more code } class A { B child = new B(); int e; } class B { int c; int d; }
V tomto případě se referenční proměnná child nachází na haldě jako součást objektu A a následně ukazuje na svůj vlastní objekt B, jak je znázorněno níže.
V čem je Odvoz odpadu Java?
Sběr odpadu v Java je proces, kterým JVM automaticky provádí správu paměti. Garbage Collector vyhledává objekty, které již nejsou dosažitelné z žádné aktivní reference, a uvolňuje jejich paměť. Dynamická alokace paměti probíhá pomocí operátoru new a paměť zůstává alokovaná, dokud program již neobsahuje žádnou referenci na daný objekt.
Pokud nezbývají žádné odkazy, objekt se považuje za nepotřebný a paměť, kterou zabírá, lze uvolnit. Není explicitně nutné objekt zničit, protože Java zpracovává dealokaci automaticky prostřednictvím Garbage Collectoru.
Technika, která za tím stojí, je známá jako Sbírka odpadkůProgramy, které se nepodaří uvolnit paměť, nakonec selžou, když už nezbývá nic k alokaci. O takových programech se říká, že mají úniky paměti. Sběr odpadu v Java běží automaticky po celou dobu životnosti programu, což odstraňuje zátěž ručního uvolňování a snižuje riziko úniků.
V jazyce C je naopak programátor zodpovědný za uvolnění paměti alokované dynamicky prostřednictvím funkce free(). Zde je situace, kdy Java Správa paměti nabízí silnou výhodu.
Moderní HotSpot JVM dodávají několik modulů Garbage Collector vyladěných pro různé úlohy. Výchozí modul G1 Garbage Collector se zaměřuje na vyváženou propustnost a doby pauz na hromadách o velikosti více gigabajtů. ZGC a Shenandoah se zaměřují na pauzy v délce menší než milisekunda na velmi velkých hromadách, což je činí...tractivní pro služby citlivé na latenci. Výběr správného kolektoru a ladění velikostí pro mladou generaci, starou generaci a metaprostor je klíčovou dovedností pro Java performativní práce.
Poznámka: Všechny objekty jsou vytvářeny v sekci Heap paměti, což je oblast spravovaná programem Garbage Collector.
Příklad: Naučit se mechanismus sběrače odpadků v Java
Tento návod ukazuje, kdy se reference stanou způsobilými pro uvolňování paměti v rámci jednoduchého programu.
Krok 1) Zkopírujte následující kód do editoru.
class Student{ int a; int b; public void setData(int c,int d){ a=c; b=d; } public void showData(){ System.out.println("Value of a = "+a); System.out.println("Value of b = "+b); } public static void main(String args[]){ Student s1 = new Student(); Student s2 = new Student(); s1.setData(1,2); s2.setData(3,4); s1.showData(); s2.showData(); //Student s3; //s3=s2; //s3.showData(); //s2=null; //s3.showData(); //s3=null; //s3.showData(); } }
Krok 2) Uložte, zkompilujte a spusťte kód. Jak je znázorněno na diagramu, vytvoří se dva objekty a dvě referenční proměnné.
Krok 3) Odkomentujte řádky 20, 21 a 22. Uložte, zkompilujte a spusťte kód.
Krok 4) Jak je znázorněno na níže uvedeném diagramu, dvě referenční proměnné nyní ukazují na stejný objekt.
Krok 5) Odkomentujte řádky 23 a 24. Uložte, zkompilujte a spusťte kód.
Krok 6) Jak je znázorněno níže, s2 se stane null, ale s3 stále odkazuje na objekt, takže objekt zatím není způsobilý pro uvolňování paměti.
Krok 7) Odkomentujte řádky 25 a 26. Uložte, zkompilujte a spusťte kód.
Krok 8) V tomto bodě na objekt neodkazují žádné odkazy, takže se stává způsobilým pro Garbage Collector. Garbage Collector jej odstraní z paměti a není možné jej znovu načíst.
Jak odstranit objekt v Java?
Java neposkytuje operátor ručního odstranění, takže standardním přístupem je odstranit všechny odkazy na objekt, aby jej Garbage Collector mohl znovu získat.
1) Chcete-li, aby byl objekt způsobilý pro uvolňování paměti (Garbage Collection), přiřaďte každé referenční proměnné, která na něj odkazuje, hodnotu null.
2) Primitivní typy nejsou objekty, takže jim nelze přiřadit hodnotu null. Jejich úložiště se automaticky uvolní, když je okolní rámec Stack odebrán.


















