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.

  • 🧠 Rozložení paměti JVM: Java Paměť je rozdělena na haldu pro objekty, zásobník pro rámce metod a lokální proměnné a vyhrazené oblasti pro bajtkód a statická data.
  • ???? Zásobník vs. halda: Rámce zásobníku se řídí pořadím „Poslední dovnitř, první ven“ a ukládají primitiva a reference, zatímco halda obsahuje všechny objekty vytvořené pomocí operátoru new.
  • ♻️ Odvoz odpadu: Sběrač odpadků tracdosažitelnost ks prostřednictvím referenčních řetězců a automaticky uvolňuje paměť od objektů, ke kterým žádné vlákno nemůže dosáhnout.
  • (Tj. Moderní sběratelé: Produkční úlohy se stále více spoléhají na G1, ZGC a Shenandoah pro sběr dat s nízkým počtem pauz napříč hromadami o velikosti více gigabajtů.
  • 🧪 Praktický příklad: Podrobný návod pro studenty ukazuje, kdy se reference stanou způsobilými pro kolekci a jak nulování referencí uvolní podkladový objekt.

Správa paměti v Java

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í:

  1. halda
  2. Stoh
  3. Code
  4. 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.

Java Zásobník a hromada

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.

Java Zásobník a hromada

Metoda m1 poté volá metodu m2. V zásobníku se vytvoří nový rámec pro m2 nad rámec pro m1.

Java Zásobník a hromada

Java Zásobník a hromada

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.

Java Zásobník a hromada

Java Zásobník a hromada

Ř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ě.

Java Zásobník a hromada

Referenční proměnná ref se vytvoří na zásobníku uvnitř rámce pro m3.

Java Zásobník a hromada

Operátor přiřazení způsobí, že referenční proměnná ukazuje na objekt na haldě.

Java Zásobník a hromada

Jakmile metoda dokončí provádění, řízení se vrátí volající metodě, kterou je v tomto případě metoda m2.

Java Zásobník a hromada

Rámec pro metodu m3 je vyprázdněn ze zásobníku.

Java Zásobník a hromada

Protože referenční proměnná již neodkazuje na objekt na haldě, stává se tento objekt způsobilým pro garbage collection.

Java Zásobník a hromada

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.

Java Zásobník a hromada

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é.

 Mechanismus sběrače odpadků

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.

Mechanismus sběrače odpadků

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.

 Mechanismus sběrače odpadků

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.

 Naučte se Garbage Collector

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.

Jak odstranit objekt v Java

Nejčastější dotazy

Stack ukládá rámce metod, lokální proměnné a reference v pořadí „Poslední dovnitř, první ven“ pro každé vlákno. Heap ukládá všechny objekty vytvořené pomocí new a je sdílen napříč vlákny, a proto jej spravuje Garbage Collector.

Garbage Collector prochází referenčními řetězci z kořenů GC, jako jsou aktivní vlákna a statická pole. Jakýkoli objekt, ke kterému nelze dosáhnout z kořene, je považován za nedosažitelný a stane se způsobilým k uvolňování během dalšího cyklu sběru.

Mladá generace uchovává krátkodobé objekty v prostorech Eden a Survivor. Stará generace uchovává objekty, které přežijí více kolekcí. Metaprostor je oblast nativní paměti, která ukládá metadata tříd a nahradila starší PermGen v... Java 8.

G1 je výchozí a vyhovuje většině úloh na hromadách o velikosti více gigabajtů. ZGC a Shenandoah cílí na submilisekundové pauzy na velmi velkých hromadách a jsou dobrou volbou pro služby citlivé na latenci běžící na Java 17 nebo novější.

Nastavte všechny reference, které odkazují na objekt, na hodnotu null, nebo nechte reference vypadnout z rozsahu platnosti, když jsou jejich Stack rámce odebrány. Jakmile k objektu nedosáhne žádná aktivní reference, Garbage Collector znovu získá svou paměť haldy.

Ano. Nástroje pro ladění řízené umělou inteligencí analyzují protokoly GC, míry alokace a histogramy pozastavení, aby doporučily velikosti hald, příznaky kolektorů a poměry Young Generation. Ve srovnání s ručním laděním zkracují dobu zpětné vazby, zejména u úloh G1, ZGC a Shenandoah.

Platformy pro pozorovatelnost založené na umělé inteligenci ingestují výpisy dat z haldy a živé metriky a poté seskupují grafy zachovaných objektů, aby označily podezřelé třídy a referenční řetězce. To odhaluje kandidáty na úniky rychleji než manuální analýza haldy a pomáhá týmům přesně určit hlavní příčinu v produkčním prostředí.

Shrňte tento příspěvek takto: