logo

Managementul memoriei în Java

În Java, managementul memoriei este procesul de alocare și dezalocare a obiectelor, numit managementul memoriei. Java gestionează automat memoria. Java folosește un sistem automat de gestionare a memoriei numit a colector de gunoi . Astfel, nu suntem obligați să implementăm logica de gestionare a memoriei în aplicația noastră. Managementul memoriei Java se împarte în două părți majore:

    Structura memoriei JVM Funcționarea Colectorului de gunoi

Structura memoriei JVM

JVM creează diferite zone de date de rulare într-un heap. Aceste zone sunt utilizate în timpul execuției programului. Zonele de memorie sunt distruse atunci când JVM iese, în timp ce zonele de date sunt distruse la ieșirea firului.

Managementul memoriei în Java

Zona metodei

Zona Metodei este o parte a memoriei heap care este partajată între toate firele. Se creează atunci când JVM-ul pornește. Este folosit pentru a stoca structura clasei, numele superclasei, numele interfeței și constructorii. JVM stochează următoarele tipuri de informații în zona metodei:

traversare în ordine
  • Un nume complet calificat de tip (ex: String)
  • Modificatorii tipului
  • Numele direct al superclasei tip
  • O listă structurată a numelor complet calificate ale super-interfețelor.

Zona Heap

Heap stochează obiectele reale. Se creează atunci când JVM-ul pornește. Utilizatorul poate controla heap-ul dacă este necesar. Poate fi de dimensiune fixă ​​sau dinamică. Când utilizați un cuvânt cheie nou, JVM-ul creează o instanță pentru obiect într-un heap. În timp ce referința acelui obiect se stochează în stivă. Există un singur heap pentru fiecare proces JVM care rulează. Când grămada devine plină, gunoiul este colectat. De exemplu:

 StringBuilder sb= new StringBuilder(); 

Declarația de mai sus creează un obiect al clasei StringBuilder. Obiectul se alocă la heap, iar referința sb se alocă la stivă. Heap-ul este împărțit în următoarele părți:

  • Generatia tanara
  • Spațiul supraviețuitorului
  • Vechea generatie
  • Generație permanentă
  • Cache de cod

Tip de referință

Există patru tipuri de referințe: Puternic , Slab , Moale , și Referință fantomă . Diferența dintre tipurile de referințe este că obiectele din hama la care se referă sunt eligibile pentru colectarea gunoiului conform diferitelor criterii.

Referință puternică: Este foarte simplu, deoarece îl folosim în programarea noastră zilnică. Orice obiect care are atașat referință puternică nu este eligibil pentru colectarea gunoiului. Putem crea o referință puternică folosind următoarea declarație:

 StringBuilder sb= new StringBuilder(); 

Referință slabă: Nu supraviețuiește după următorul proces de colectare a gunoiului. Dacă nu suntem siguri când vor fi solicitate din nou datele. În această condiție, putem crea o referință slabă la ea. În cazul în care, dacă colectorul de gunoi procesează, acesta distruge obiectul. Când încercăm din nou să recuperăm acel obiect, obținem o valoare nulă. Este definit în java.lang.ref.WeakReference clasă. Putem crea o referință slabă utilizând următoarea declarație:

 WeakReference reference = new WeakReference(new StringBuilder()); 

Referință soft: Acesta este colectat atunci când aplicația nu dispune de memorie. Colectorul de gunoi nu colectează obiectele ușor accesibile. Toate obiectele de referință soft sunt colectate înainte ca acesta să afișeze un OutOfMemoryError. Putem crea o referință soft folosind următoarea declarație:

 SoftReference reference = new SoftReference(new StringBuilder()); 

Referință fantomă: Este disponibil în java.lang.ref pachet. Este definit în java.lang.ref.PhantomReference clasă. Obiectul care are doar referință fantomă care le îndreaptă poate fi colectat ori de câte ori colectorul de gunoi dorește să colecteze. Putem crea o referință fantomă utilizând următoarea declarație:

 PhantomReference reference = new PhantomReference(new StringBuilder()); 

Zona stivei

Stack Area se generează atunci când se creează un fir. Poate fi de dimensiune fixă ​​sau dinamică. Memoria stivei este alocată per fir. Este folosit pentru stocarea datelor și a rezultatelor parțiale. Conține referințe la obiecte heap. De asemenea, deține valoarea în sine, mai degrabă decât o referință la un obiect din heap. Variabilele care sunt stocate în stivă au o anumită vizibilitate, numită scope.

Stack Frame: Stack frame este o structură de date care conține datele firului. Datele firului reprezintă starea firului în metoda curentă.

  • Este folosit pentru a stoca rezultate și date parțiale. De asemenea, efectuează legături dinamice, valori returnate prin metode și excepții de expediere.
  • Când o metodă invocă, se creează un nou cadru. Distruge cadrul când invocarea metodei se încheie.
  • Fiecare cadru conține propria matrice de variabile locale (LVA), stiva de operanzi (OS) și date cadru (FD).
  • Dimensiunile LVA, OS și FD determinate în timpul compilării.
  • Doar un cadru (cadru pentru metoda de execuție) este activ în orice punct dintr-un anumit fir de control. Acest cadru se numește cadru curent, iar metoda sa este cunoscută ca metoda curentă. Clasa metodei se numește clasa curentă.
  • Cadrul oprește metoda curentă, dacă metoda ei invocă o altă metodă sau dacă metoda se finalizează.
  • Cadrul creat de un fir este local pentru acel fir și nu poate fi referit de niciun alt fir.

Stiva de metode native

Este cunoscut și ca stiva C. Este o stivă pentru codul nativ scris într-o altă limbă decât Java. Java Native Interface (JNI) apelează stiva nativă. Performanța stivei native depinde de sistemul de operare.

care este cazul în sql

Registre PC

Fiecare thread are asociat un registru Program Counter (PC). Registrul PC stochează adresa de retur sau un pointer nativ. Conține, de asemenea, adresa instrucțiunilor JVM în curs de executare.

Funcționarea Colectorului de gunoi

Prezentare generală a colectorului de gunoi

Când un program se execută în Java, folosește memoria în moduri diferite. Heap-ul este o parte a memoriei în care trăiesc obiectele. Este singura parte a memoriei implicată în procesul de colectare a gunoiului. Este cunoscut și sub numele de grămada de gunoi de colectare. Toată colectarea gunoiului se asigură că grămada are cât mai mult spațiu liber posibil. Funcția colectorului de gunoi este de a găsi și șterge obiectele care nu pot fi atinse.

Alocarea obiectelor

Când un obiect se alocă, JRockit JVM verifică dimensiunea obiectului. Face distincția între obiectele mici și cele mari. Dimensiunea mică și mare depinde de versiunea JVM, dimensiunea heap-ului, strategia de colectare a gunoiului și platforma utilizată. Dimensiunea unui obiect este de obicei între 2 și 128 KB.

Obiectele mici sunt stocate în Thread Local Area (TLA), care este o bucată liberă din heap. TLA nu se sincronizează cu alte fire. Când TLA devine plin, acesta solicită un nou TLA.

Pe de altă parte, obiectele mari care nu se potrivesc în interiorul TLA sunt alocate direct în grămada. Dacă un fir folosește spațiul tânăr, acesta este stocat direct în spațiul vechi. Obiectul mare necesită mai multă sincronizare între fire.

Ce înseamnă Java Garbage Collector?

JVM controlează colectorul de gunoi. JVM decide când să efectueze colectarea gunoiului. De asemenea, putem solicita JVM-ului să ruleze colectorul de gunoi. Dar nu există nicio garanție în nicio condiție că JVM-ul se va conforma. JVM rulează colectorul de gunoi dacă detectează că memoria se epuizează. Atunci când programul Java solicită colectorul de gunoi, JVM-ul acordă de obicei cererea în scurt timp. Nu se asigură că cererile acceptă.

Ideea de înțeles este că ' când un obiect devine eligibil pentru colectarea gunoiului? '

Fiecare program Java are mai mult de un fir. Fiecare thread are stiva sa de execuție. Există un fir de rulare în programul Java care este o metodă main(). Acum putem spune că un obiect este eligibil pentru colectarea gunoiului atunci când niciun fir live nu îl poate accesa. Colectorul de gunoi consideră că acel obiect este eligibil pentru ștergere. Dacă un program are o variabilă de referință care se referă la un obiect, acea variabilă de referință disponibilă pentru firul live, acest obiect este apelat accesibil .

Aici apare o întrebare că ' Poate o aplicație Java să rămână fără memorie? '

Raspunsul este da. Sistemul de colectare a gunoiului încearcă să extragă obiecte din memorie atunci când acestea nu sunt utilizate. Cu toate acestea, dacă întrețineți multe obiecte active, colectarea gunoiului nu garantează că există suficientă memorie. Doar memoria disponibilă va fi gestionată eficient.

Tipuri de colectare a gunoiului

Există cinci tipuri de colectare a gunoiului, după cum urmează:

    GC serial:Utilizează abordarea marca și mătură pentru generațiile tinere și bătrâne, care este GC minoră și majoră.GC paralel:Este similar cu GC serial, cu excepția faptului că generează N (numărul de nuclee CPU din sistem) fire pentru colectarea de gunoi de generație tânără.Vechi GC paralel:Este similar cu GC paralel, cu excepția faptului că folosește mai multe fire pentru ambele generații.Colector Concurrent Mark Sweep (CMS):Face colectarea gunoiului pentru vechea generație. Puteți limita numărul de fire în colectorul CMS folosind XX:ParalleCMSThreads=Opțiune JVM . Este cunoscut și sub numele de colector de pauză scăzută simultană.Colector de gunoi G1:A fost introdus în Java 7. Obiectivul său este să înlocuiască colectorul CMS. Este un colector paralel, concurent și CMS. Nu există spațiu pentru generațiile tinere și bătrâne. Împarte grămada în mai multe mormane de dimensiuni egale. Mai întâi colectează regiunile cu mai puține date live.

Algoritmul Mark and Sweep

JRockit JVM folosește algoritmul de marcare și măturare pentru a efectua colectarea gunoiului. Conține două faze, faza de marcare și faza de măturare.

Faza de marcare: Obiectele care sunt accesibile din fire, handle native și alte surse rădăcină GC sunt marcate ca live. Fiecare arbore de obiecte are mai multe obiecte rădăcină. Rădăcina GC este întotdeauna accesibilă. Deci orice obiect care are o rădăcină de colectare a gunoiului la rădăcină. Identifică și marchează toate obiectele care sunt în uz, iar cele rămase pot fi considerate gunoi.

Managementul memoriei în Java

Faza de măturare: În această fază, grămada este parcursă pentru a găsi decalajul dintre obiectele vii. Aceste lacune sunt înregistrate în lista liberă și sunt disponibile pentru alocarea de noi obiecte.

Există două versiuni îmbunătățite de marcare și măturare:

    Marcare și măturare simultane Marcare paralelă și măturare

Marcare și măturare simultane

Permite firelor de execuție să continue să ruleze în timpul unei mari părți a colectării gunoiului. Există următoarele tipuri de marcare:

algoritmul kruskal
    Marcarea inițială:Identifică setul rădăcină de obiecte active. Se face în timp ce firele sunt întrerupte.Marcare concomitentă:În acest marcaj, sunt urmate referințele din setul rădăcină. Găsește și marchează restul obiectelor vii într-o grămadă. Se face în timp ce firul rulează.Marcaj de pre-curățare:Identifică modificările efectuate prin marcarea concomitentă. Alte obiecte vii marcate și găsite. Se face în timp ce firele rulează.Marcaj final:Identifică modificările efectuate prin marcarea pre-curățare. Alte obiecte vii marcate și găsite. Se face în timp ce firele sunt întrerupte.

Marcare paralelă și măturare

Folosește tot procesorul disponibil în sistem pentru a efectua colectarea gunoiului cât mai repede posibil. Se mai numește și colectorul de gunoi paralel. Threadurile nu se execută atunci când se execută colectarea de gunoi în paralel.

Avantajele Mark și Sweep

  • Este un proces recurent.
  • Este o buclă infinită.
  • Nu sunt permise cheltuieli suplimentare în timpul execuției unui algoritm.

Dezavantajele lui Mark și Sweep

  • Oprește execuția normală a programului în timp ce algoritmul de colectare a gunoiului rulează.
  • Se rulează de mai multe ori pe un program.