Managementul memoriei în Java

⚡ Rezumat inteligent

Managementul memoriei în Java explică modul în care JVM împarte memoria de execuție între Stack, Heap, Codeși regiuni statice, modul în care se desfășoară referințele la obiecte în timpul apelurilor de metode și modul în care Garbage Collector recuperează obiectele inaccesibile, astfel încât aplicațiile să rămână stabile și fără pierderi de memorie.

  • 🧠 Aspectul memoriei JVM: Java memoria este împărțită în Heap pentru obiecte, Stack pentru cadrele de metode și variabile locale, plus zone dedicate pentru bytecode și date statice.
  • 📚 Stivă vs. Heap: Frame-urile stivă urmează ordinea Ultimul intrat, primul ieșit și stochează primitive și referințe, în timp ce Heap-ul conține fiecare obiect creat cu operatorul new.
  • ♻️ Colectarea gunoiului: Colectorul de gunoi tracAccesibilitatea lui ks prin lanțuri de referințe și recuperează automat memoria de la obiectele pe care niciun thread nu le poate atinge.
  • Colecționari moderni: Volumurile de lucru de producție se bazează din ce în ce mai mult pe G1, ZGC și Shenandoah pentru colectarea cu pauză redusă pe heap-uri de mai mulți gigaocteți.
  • 🧪 Exemplu practic: O prezentare pas cu pas a clasei Student arată când referințele devin eligibile pentru colectare și cum anularea referințelor eliberează obiectul subiacent.

Managementul memoriei în Java

Ce este memoria stivă în Java?

Memoria stivuită în Java este regiunea din memoria JVM care stochează cadrele de metodă, variabilele locale și variabilele de referință pentru fiecare fir de execuție. Stiva este întotdeauna accesată în ordinea „Ultimul intrat, primul ieșit”, astfel încât metoda invocată cel mai recent se află deasupra, iar variabilele sale locale sunt introduse și extrase odată cu cadrul.

Fiecare fir din Java Mașina virtuală primește propriul Stack, care menține invocările metodelor izolate și sigure pentru thread-uri prin design. Valorile locale primitive, cum ar fi int, boolean și double, se află direct în interiorul frame-ului, în timp ce referințele obiectelor stocate pe Stack indică obiecte alocate pe Heap.

Ce este memoria Heap în Java?

Memoria heap este regiunea JVM partajată care conține fiecare Java obiect și matrice create cu operatorul new, împreună cu orice variabile de referință care aparțin acelor obiecte ca și câmpuri de instanță. Spre deosebire de Stack, Heap-ul este partajat între toate firele de execuție, motiv pentru care accesul la obiecte necesită adesea sincronizare.

Heap-ul este zona gestionată de Garbage Collector. JVM-urile HotSpot moderne împart Heap-ul într-o Generație Tânără pentru obiectele cu durată scurtă de viață și o Generație Veche pentru obiectele cu durată lungă de viață, metadatele clasei fiind stocate într-o regiune nativă separată numită Metaspace.

Alocarea memoriei în Java

Alocarea memoriei în Java este procesul prin care JVM rezervă regiuni de memorie virtuală pentru variabile și instanțe de clase și structuri în timpul execuției programului. Memoria nu este alocată unui obiect la declarare; este creată doar o referință. Alocarea propriu-zisă a obiectului are loc prin operatorul new, astfel încât fiecare obiect se află în Heap.

Java Alocarea memoriei este împărțită în următoarele secțiuni:

  1. movilă
  2. Stivui
  3. Code
  4. Static

Această diviziune a memoriei este necesară pentru gestionarea eficientă a timpului de execuție.

  • Code secțiunea conține compilarea dvs. cod octet.
  • Stivui magazine de secție metode, variabile locale și variabile de referință.
  • movilă secțiunea conține obiecte și poate conține, de asemenea, variabile de referință păstrate ca și câmpuri de instanță.
  • Static secțiunea deține date statice și metode statice partajată în toate instanțele.

Diferența dintre variabila locală și variabila de instanță

Înțelegerea locului în care se află fiecare tip de variabilă în JVM ajută la explicarea comportamentului Stack și Heap. variabila de instanta este declarat în interiorul unei clase, dar în afara oricărei metodeși se află pe Heap ca parte a obiectului său.

class Student{ 
int num; // num is instance variable 
public void showData{}

A variabila locala este declarat în interiorul unei metode, inclusiv argumentele metodeiși se află pe Stiva din interiorul cadrului activ.

public void sum(int a){

int x = a + 3;

// a, x are local variables

}

Diferența dintre stack și heap

Stiva și Heap-ul rezolvă probleme diferite în interiorul JVM-ului. Stiva oferă fiecărui fir de execuție o alocare rapidă și deterministă pentru datele cu durată scurtă de viață legate de domeniul de aplicare al metodei, în timp ce Heap-ul oferă o regiune partajată pentru obiectele cu durată lungă de viață la care orice fir de execuție poate face referire. Scurtul videoclip de mai jos rezumă contrastul înainte de ghidul următor.

Clic aici dacă videoclipul nu este accesibil

Pentru a vedea cum cooperează Stack și Heap, luați în considerare o metodă main care apelează metoda m1.

public void m1{
int x = 20;
}

În JVM Stack, se creează un frame pentru metoda m1.

Java Stack and Heap

Variabila x din m1 este creată și în cadrul pentru m1 pe Stivă, așa cum se arată în imaginea de mai jos.

Java Stack and Heap

Metoda m1 apelează apoi metoda m2. În Stivă, se creează un nou cadru pentru m2 deasupra cadrului pentru m1.

Java Stack and Heap

Java Stack and Heap

Variabilele locale b și c sunt, de asemenea, create în interiorul cadrului pentru m2 pe Stivă.

public void m2(int b){
boolean c;
}

Apoi, m2 apelează metoda m3. Din nou, un cadru pentru m3 este creat în partea de sus a stivei, așa cum se arată mai jos.

Java Stack and Heap

Java Stack and Heap

Acum, să presupunem că metoda m3 creează un obiect pentru clasa Account, care are două variabile de instanta int p și int q.

class Account {
    int p;
    int q;
}

Iată codul pentru metoda m3.

public void m3(){
    Account ref = new Account();
    // more code
}

Instrucțiunea new Account() creează un obiect de tip Account în Heap.

Java Stack and Heap

Variabila de referință ref este creată pe Stiva în interiorul cadrului pentru m3.

Java Stack and Heap

Operatorul de atribuire face ca variabila de referință să indice către obiectul din Heap.

Java Stack and Heap

Odată ce metoda finalizează execuția, controlul revine la metoda apelantă, care în acest caz este metoda m2.

Java Stack and Heap

Cadrul pentru metoda m3 este golit din Stivă.

Java Stack and Heap

Deoarece variabila de referință nu mai indică obiectul din Heap, acel obiect devine eligibil pentru colectarea gunoiului.

Java Stack and Heap

Odată ce metoda m2 s-a terminat, aceasta este eliminată din Stivă și toate variabilele sale devin indisponibile. Același lucru se întâmplă și cu metoda m1, iar în cele din urmă controlul revine la metoda principală.

Ce se întâmplă dacă un obiect deține o altă referință ca variabilă de instanță?

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;
}

În acest caz, variabila de referință copil se află pe Heap ca parte a obiectului A și, la rândul său, indică propriul obiect B, așa cum se arată mai jos.

Java Stack and Heap

În ce este colectarea gunoiului Java?

Colectarea gunoiului în Java este procesul prin care JVM efectuează automat gestionarea memoriei. Colectorul de gunoi găsește obiecte care nu mai sunt accesibile din nicio referință live și le recuperează memoria. Alocarea dinamică a memoriei se face prin intermediul operatorului new, iar memoria rămâne alocată până când programul nu mai deține nicio referință la obiect.

Când nu mai rămân referințe, obiectul este considerat a nu mai fi necesar, iar memoria pe care o ocupă poate fi recuperată. Nu există o nevoie explicită de a distruge un obiect deoarece Java gestionează automat dealocarea prin intermediul Colectorului de gunoi.

Tehnica din spatele acestui lucru este cunoscută sub numele de Colecția de gunoiProgramele care nu reușesc să elibereze memorie se blochează în cele din urmă atunci când nu mai rămâne nimic de alocat. Se spune că astfel de programe au scurgeri de memorie. Colectarea gunoiului în Java rulează automat pe toată durata de viață a programului, ceea ce elimină povara deallocării manuale și reduce riscul de scurgeri.

În C, prin contrast, programatorul este responsabil pentru eliberarea memoriei alocate dinamic prin funcția free(). Aici este locul unde Java gestionarea memoriei oferă un avantaj semnificativ.

JVM-urile HotSpot moderne includ mai multe colectoare de gunoi optimizate pentru diferite sarcini de lucru. Colectorul de gunoi G1 implicit vizează un debit echilibrat și timpi de pauză pe heap-uri de mai mulți gigabytes. ZGC și Shenandoah vizează pauze sub milisecunde pe heap-uri foarte mari, ceea ce le face...tractiv pentru servicii sensibile la latență. Alegerea colectorului potrivit și reglarea dimensiunilor Generației Tânăre, Generației Vechi și Metaspațiului reprezintă o abilitate esențială pentru Java muncă de performanță.

Notă: Toate obiectele sunt create în secțiunea Heap a memoriei, care este regiunea gestionată de Garbage Collector.

Exemplu: Pentru a învăța mecanismul de colectare a gunoiului în Java

Această demonstrație prezintă momentele în care referințele devin eligibile pentru Garbage Collection în cadrul unui program simplu.

Pas 1) Copiați următorul cod într-un editor.

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();
  }
}

Pas 2) Salvați, compilați și rulați codul. După cum se arată în diagramă, sunt create două obiecte și două variabile de referință.

 Mecanism de colectare a gunoiului

Pas 3) Eliminați comentariile de la liniile 20, 21 și 22. Salvați, compilați și rulați codul.

Pas 4) După cum se arată în diagrama de mai jos, două variabile de referință indică acum același obiect.

Mecanism de colectare a gunoiului

Pas 5) Eliminați comentariile de la liniile 23 și 24. Salvați, compilați și rulați codul.

Pas 6) După cum se arată mai jos, s2 devine nul, dar s3 indică în continuare obiectul, deci obiectul nu este încă eligibil pentru Garbage Collection.

 Mecanism de colectare a gunoiului

Pas 7) Eliminați comentariile de la liniile 25 și 26. Salvați, compilați și rulați codul.

Pas 8) În acest moment, nicio referință nu indică către obiect, deci acesta devine eligibil pentru Garbage Collector. Garbage Collector îl elimină din memorie și nu există nicio modalitate de a-l recupera.

 Învață Garbage Collector

Cum se șterge un obiect în Java?

Java nu oferă un operator de ștergere manuală, așadar abordarea standard este de a elimina fiecare referință la obiect, astfel încât Garbage Collector să îl poată recupera.

1) Pentru a face un obiect eligibil pentru Garbage Collection, atribuiți fiecărei variabile de referință care indică către acesta valoarea nulă.

2) Tipurile primitive nu sunt obiecte, deci nu li se poate atribui valoarea nulă. Spațiul lor de stocare este recuperat automat atunci când se extrage frame-ul Stack din jur.

Cum să ștergeți un obiect în Java

Întrebări frecvente

Stiva stochează cadrele de metode, variabilele locale și referințele în ordinea „Ultimul intrat, primul ieșit” per fir de execuție. Heap-ul stochează toate obiectele create cu new și este partajat între fire de execuție, motiv pentru care Garbage Collector îl gestionează.

Colectorul de gunoi parcurge lanțurile de referință de la rădăcinile GC, cum ar fi thread-urile active și câmpurile statice. Orice obiect care nu poate fi accesat de la o rădăcină este considerat inaccesibil și devine eligibil pentru recuperare în timpul următorului ciclu de colectare.

Generația Tânără deține obiecte cu viață scurtă în spațiile Eden și Survivor. Generația Veche deține obiecte care supraviețuiesc mai multor colecții. Metaspațiul este o regiune de memorie nativă care stochează metadatele clasei și a înlocuit vechiul PermGen în Java 8.

G1 este implicit și se potrivește majorității sarcinilor de lucru pe heap-uri de mai mulți gigabytes. ZGC și Shenandoah vizează pauzele sub milisecunde pe heap-uri foarte mari și sunt alegeri bune pentru serviciile sensibile la latență care rulează pe Java 17 sau versiuni ulterioare.

Setați fiecare referință care indică către obiect la nulă sau lăsați referințele să iasă din domeniul de aplicare atunci când cadrele lor Stack sunt deblocate. Odată ce nicio referință activă nu ajunge la obiect, Garbage Collector își recuperează memoria Heap.

Da. Instrumentele de optimizare bazate pe inteligență artificială analizează jurnalele GC, ratele de alocare și histogramele de pauză pentru a recomanda dimensiuni ale heap-urilor, semnalizatoare de colectori și rapoarte Young Generation. Acestea scurtează bucla de feedback în comparație cu optimizarea manuală, în special în sarcinile de lucru G1, ZGC și Shenandoah.

Platformele de observabilitate bazate pe inteligență artificială ingerează heap dumps și metrici live, apoi grupează graficele obiectelor reținute pentru a semnala clasele suspecte și a face referire la lanțuri. Acest lucru scoate la iveală candidați de scurgeri mai rapid decât analiza manuală a heap-ului și ajută echipele să identifice cauza principală în producție.

Rezumați această postare cu: