31
Exceptii Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014 Ioan Asiminoaei 1 Exceptii. Garbage Collection. Automatic Memory Management - Garbage Collection Probleme tratate Exceptii Definirea unei exceptii. Exceptii sistem. Clasa Exception. Blocurile try, catch, finally. Garbage Collection. Alocare memorie si initializare resurse. Finalizare – Destructor in C#. Directiva using. Generatii. Clasa GC. Pattern-ul Dispose. Interfata IDisposable.

Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

  • Upload
    others

  • View
    12

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 1

Exceptii. Garbage Collection.

Automatic Memory Management - Garbage Collection

Probleme tratate

Exceptii

• Definirea unei exceptii.

• Exceptii sistem. Clasa Exception.

• Blocurile try, catch, finally.

Garbage Collection.

• Alocare memorie si initializare resurse.

• Finalizare – Destructor in C#. Directiva using.

• Generatii.

• Clasa GC.

• Pattern-ul Dispose.

• Interfata IDisposable.

Page 2: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 2

Exceptii

Ce este o exceptie?

Termenul eroare indica ca programatorul a facut ceva gresit.

Exceptiile nu indica neaparat o eroare in cod.

Exceptiile nu conduc neaparat la oprirea executiei unei aplicatii.

O exceptie poate fi definita ca fiind violarea unei presupuneri implicite asupra unei

interfete (J. Richter).

O linie de cod poate sa nu se execute corect din diverse motive: depasire aritmetica,

depasire stiva, memorie insuficienta, indici in afara intervalului, etc.

O aplicatie ce si-ar propune sa verifice toate (sau aproape toate) posibilitatile ce pot

aparea in executarea unei linii de cod si-ar pierde din claritate, ar fi foarte greu de

intretinut, iar mare parte din timp procesor s-ar consuma cu aceste verificari.

Realizarea unei astfel de aplicatii este aproape imposibila.

Folosind exceptiile nu este nevoie sa scriem cod pentru a detecta toate aceste posibile

caderi. In plus codul se executa mai rapid.

Trebuie spus de la inceput ca exceptiile genereaza alte probleme care trebuiesc rezolvate.

Dintre avantajele introducerii exceptiilor amintim :

• Abilitatea de a mentine cod clar si de a intelege logica aplicatiei mai usor.

• Posibilitatea de a detecta si localiza bug-uri in cod.

• Exceptia include un sir de caractere ce o descrie.

• Sirul de caractere contine o cale catre apelul ce a declansat anomalia. Informatiile

se gasesc pe stiva.

Cand apare o “cadere”, CLR scaneaza stiva firului cautand codul ce ar putea trata

exceptia. Daca nu exista un asemenea cod, primim o notificare “unhandled exception”.

Folosirea incorecta a tratarii execeptiilor poate crea neplaceri mai mari decat nefolosirea

lor.

Evolutia manipularii exceptiilor

Win32 API si COM nu folosesc exceptiile pentru a notifica utilizatorul despre

problema aparuta. Multe functii returneaza FALSE sau NULL sau o valoare de tip

HRESULT pentru a indica ca ceva nu s-a executat corect. De altfel nu s-a standardizat

tratarea erorilor in Win32 API. La inceput C si C++ nu suportau exceptiile.

Metoda veche de raportare a erorilor se limita la un numar pe 32 de biti. In marea

majoritate a cazurilor mesajele nu sunt clare si nu ofera suficienta informatie pentru a

detecta ce anume s-a intimplat.

Page 3: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 3

Exceptiile nu pot fi ignorate. Daca aplicatia nu trateaza exceptia, CLR termina aplicatia.

Daca o metoda genereaza o exceptie, aceasta inseamna ca nu lucreaza asa cum ar trebui.

Toate metodele definite de tipurile din cadrul de lucru .NET genereaza exceptii pentru a

indica ca anumite presupuneri au fost incalcate. Nu se returneaza nici o valoare de stare.

Mecanismul manipularii exceptiilor

Mecanismul de manipulare al exceptiilor cadrului de lucru .NET este construit folosind

“Structured Exception Handling” (SEH).

Urmatorul cod C# arata o folosire standard a mecanismului de tratare al exceptiilor.

void Metoda() {

try {

// aici scriem codul ce vrem sa-l protejam (supus verificarii) }

catch (InvalidCastException) { // Aici este codul ce se va executa daca apare exceptia // InvalidCastException sau orice exceptie a unui // tip derivat din InvalidCastException. } catch (NullReferenceException) { // Aici este codul ce se va executa daca apare exceptia // NullReferenceException sau orice exceptie a unui // tip derivat din NullReferenceException. } catch (Exception e) { // In interiorul acestui bloc scriem codul care se executa // pentru o exceptie CLS-compliant (conforma cu CLS). // In mod normal se rearunca exceptia.

throw; }

catch { // Aici este codul ce se va executa pentru orice tip de exceptie // In mod normal se rearunca exceptia.

throw; } finally {

// Acest cod este garantat ca se executa totdeauna, dar // binenteles exista cateva exceptii de la // aceasta presupunere. // Codul de aici se executa indiferent daca a aparut // sau nu o exceptie. // Este asa numitul cod de curatare, mai precis

Page 4: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 4

// de terminare // a unor operatii incepute in bocul try.

}

//

// In continuare este codul ce se executa cand nu // a aparut nici o exceptie.

}

In mod normal in cod avem un bloc try, unul sau mai multe blocuri catch si optional un

bloc finally.

Blocul try

In general un bloc try contine cod ce are nevoie de operatii de terminare corecta

(curatare) sau operatii de tratare a exceptiilor.

� Codul pentru terminare corecta a blocului try (de ex. inchiderea unui fisier)

trebuie plasat in blocul finally.

� Codul de tratare al exceptiilor trebuie plasat in unul sau mai multe blocuri catch.

� Fiecare bloc catch identifica un anumit tip de exceptie.

Putem crea cate un bloc catch pentru orice tip de eveniment pentru care avem

posibilitatea de a corecta exceptia aparuta sau a obtine mai multe informatii despre

aceasta. Aceste informatii pot ajuta pentru depistarea unui bug sau neindeplinirea unor

conditii de sistem.

Un bloc try trebuie sa fie asociat cu cel putin un bloc catch sau finally.

Blocul catch

Blocul catch contine cod ce se executa cand apare o exceptie. Daca codul din

blocul try nu cauzeaza o exceptie, atunci codul din blocul catch nu se executa. Daca

exista blocul finally atunci codul se executa indiferent daca s-a aruncat sau nu o exceptie.

Expresia dintre paranteze de la blocul catch se numeste “filtru exceptie”.

Exceptia filtru este un tip ce reprezinta o situatie exceptionala pe care dezvoltatorul a

anticipat-o si poate sa o trateze intr-un anume fel (poate iesi din aceasta situatie).

In C#, tipul din “filtru” trebuie sa fie System.Exception sau un tip derivat din

System.Exception.

Page 5: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 5

� Blocurile catch sunt tratate in mod secvential, de sus in jos, deci blocurile

catch pentru tratarea exceptiilor specifice trebuie plasate cat mai aproape

de blocul try.

Daca o exceptie este generata de codul din blocul try (sau orice metoda apelata

din cadrul acestuia), CLR cauta blocurile catch al caror filtru se potriveste cu exceptia

aruncata. Daca nu exista un asemenea bloc catch, atunci CLR cauta in stiva un bloc catch

al carui filtru se potriveste. Daca cautarea s-a terminat si nu s-a gasit un asemenea bloc

atunci CLR opreste aplicatia si afiseaza mesajul “Unhandled exception”.

CLR pastreaza o arborescenta a tuturor metodelor apelate din blocul try.

Cand s-a localizat un bloc catch ce trateaza excepia (filtrul se potriveste), CLR executa

codul din toate blocurile finally, plecand de la acela al blocului try ce a generat exceptia

si oprindu-se la acela al blocului try ce contine blocul catch ce trateaza exceptia.

Codul din ultimul bloc finally se va executa dupa ce s-a executat codul din blocul catch.

In C#, un filtru catch poate specifica o variabila de tip exceptie. Aceasta variabila se

refera la un obiect derivat din System.Exception ce a aruncat aceasta exceptie. Codul din

blocul catch poate referi aceasta variabila pentru a obtine informatii suplimentare despre

exceptie.

La sfarsitul ultimului bloc catch avem urmatoarele posibilitati:

1. “regenerarea” aceleasi exceptii;

2. generarea unei alte exceptii;

3. sa lasam ca firul sa termine cautarea aici.

In primele doua situatii, CLR va cauta in continuare pe stiva un bloc catch ce poate trata

exceptia.

In ultima situatie se va executa codul din blocul finally si apoi se continua in secventa cu

codul ce urmeaza acestui bloc. Daca nu exista un bloc finally, se continua executia cu

codul ce urmeaza ultimului bloc catch.

Blocul finally

Un bloc finally contine cod ce este garantat ( ?!) ca se va executa.

Exemplu:

void ReadData(String pathname) {

FileStream fs = null; try {

fs = new FileStream(pathname, FileMode.Open); // Procesare date din fisier

} catch (OverflowException) {

Page 6: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 6

// Cod de tratare a exceptiei OverflowException // sau a oricarui tip de exceptie derivat din OverflowException } finally {

// Ne asiguram sa inchidem fisierul if (fs != null) fs.Close();

} }

Indiferent de cum se executa codul din blocul try, codul din blocul finally se va executa.

Blocul finally trebuie sa apara dupa toate blocurile catch asociate cu blocul try.

Nu se genereaza exceptii in blocul finally. Riscul este de a construi o aplicatie ce nu se

mai termina.

Exceptii generate de aplicatie. Exceptii generate de CLR.

Trebuie sa facem distinctie intre exceptiile generate de aplicatie si cele generate de CLR.

Comportarile aplicatiei sunt diferite functie de cine a generat exceptia.

CLR arunca exceptii, de ex. System.StackOverflowException, sau

System.OutOfMemoryException, sau System.ExecutionEngineException.

Codul din blocul finally este posibil sa nu se poata executa in cazul exceptiilor de mai

sus.

OutOfMemoryException = este generata aceasta exceptie cand construim un nou

obiect si nu exista memorie suficienta. In acest caz procesul se termina imediat, codul din

blocul finally se executa. Daca exceptia este aruncata de CLR atunci procesul se termina

imediat si aplicatia nu mai este in stare sa prinda aceasta exceptie si blocul finally nu se

mai executa.

StackOverflowException = CLR arunca aceasta exceptie cand un fir a utilizat tot

spatiul pentru stiva. Aplicatia poate prinde aceasta exceptie dar codul din blocul finally

nu se va executa pentru ca si asta are nevoie de spatiu pe stiva.

Fiecare bloc catch ce prinde aceasta exceptie trebuie sa o « arunce » in continuare

(rethrow) pentru a da sansa CLR-ului sa termine procesul.

Daca exceptia apare in CLR, aplicatia nu poate prinde aceasta exceptie si blocul finally

nu se executa. In acest caz CLR termina procesul sau lanseaza un debugger.

ExecutionEngineException = CLR arunca aceasta exceptie cand detecteaza ca

structurile sale de date interne sunt corupte sau are anumite bug-uri. CLR-ul termina

procesul sau va lansa un debugger pentru proces. Nu se executa nici un bloc catch si nici

finally.

Page 7: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 7

Clasa System.Exception Modelul de tratare al exceptiilor este bazat pe reprezentarea exceptiilor ca obiecte si

separarea codului aplicatiei de codul de tratatre al exceptiilor.

Un bloc catch ce trateaza System.Exception trebuie sa fie ultimul bloc pentru try.

Ordinea blocurilor catch ce trateaza o exceptie va fi urmatoarea :

• intai exceptia pentru tipul derivat

• apoi exceptia pentru clasa de baza (blocurile catch se trateaza secvential, iar

cautarea se opreste dupa primul bloc catch ce trateaza exceptia).

Exemplu (cod incorect – al doilea bloc catch nu va fi « executat » niciodata pentru ca

System.Web.HttpException este derivat din System.Exception).

try { // Code which can cause a web exception or arithmetic exception. } catch (System.Exception ex) { MessageBox.Show ( "An exception occurred." ); } catch (System.Web.HttpException ex) { MessageBox.Show ( "A web exception occurred." ); }

Acelasi exemplu, dar de aceasta data corect:

try { // Code which can cause a web exception or arithmetic exception. } catch (System.Web.HttpException ex) { MessageBox.Show ( "A web exception occurred." ); } catch(System.Exception ex) { MessageBox.Show ( "An exception occurred." ); }

In clasa Exception exista doua categorii de exceptii:

• clase exceptii predefinite de CLR, derivate din System.Exception.

• Clase exceptii definite de utilizator la nivel de aplicatie si derivate din

ApplicationException.

Page 8: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 8

Tipurile de exceptii ce sunt derivate din System.Exception se numesc CLS-compliant

(conforme cu CLS).

Tipul System.Exception este descris in continuare.

Proprietati :

Message - Read-only String – Un mesaj ce descrie exceptia generata.

Source - Read/write String – Contine numele assembly-ului ce a generat exceptia.

StackTrace - Read-only String – Contine numele si signatura metodei apelate ce a dus

la generarea exceptiei.

TargetSite - Read-only MethodBase – Contine metoda ce a generat exceptia.

HelpLink - Read-only String – Contine un URL la documentatia exceptiei.

InnerException - Read-only Exception – Indica exceptia anterioara daca exceptia

curenta a fost generata in timp ce manipula o alta exceptie.

Metoda GetBaseException returneaza originea exceptiei.

HResult - Read/write Int32 – Proprietate protected, folosita cand exista cod managed si

unmanaged COM.

ApplicationException:

� ApplicationException este generata de un cod al utilizatorului si nu

de CLR. In mod normal exceptiile create de utilizator ar trebui derivate

din acest tip.

� ApplicationException diferentiaza exceptiile definite de utilizator de

cele definite de sistem.

� ApplicationException nu furnizeaza informatii despre cauza

exceptiei. In mod normal nu se genereaza o asemenea exceptie de catre

aplicatie, dar in cazul cand se face acest lucru se va pasa constructorului

clasei un mesaj ce va descrie cauza aparitiei exceptiei.

Pentru mai multe detalii consultati documentatia Microsoft.

Page 9: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 9

Clase exceptii folosite in mod frecvent

System.ArithmeticException – exceptii ce apar in timpul operatiilor aritmetice,

cum ar fi System.DivideByZeroException and System.OverflowException.

System.ArrayTypeMismatchException - ArrayTypeMismatchException este

generata cand un obiect incompatibil se incearca a fi memorat intr-un Array.

System.DivideByZeroException – incercare de impartire prin zero.

System.IndexOutOfRangeException - IndexOutOfRangeException este generata

cand se incearca sa se acceseze un tablou folosind un index mai mic ca zero sau in afara

intervalului.

System.InvalidCastException – aruncata cand o conversie implicita de la tipul de

baza sau interfata la tipul derivat nu se executa corect in momentul executiei.

System.NullReferenceException – generata cand se foloseste o referinta null la un

obiect pentru a-l accesa.

System.OutOfMemoryException - OutOfMemoryException este generata cand

operatia 'new' (crearea unui nou obiect) nu se executa cu succes pentru ca nu exista

suficienta memorie.

System.OverflowException - OverflowException este generata cand apare depasire

la executia unei operatii aritmetice.

System.StackOverflowException - StackOverflowException este generata cand

cand stiva de executie este prea mica pentru a executa toate apelurile initiate (probabil

bucla infinita).

ArgumentException – exceptie generata cand un argument furnizat unei metode este

invalid.

Metodele definite de tipurile din FCL sunt presupuse ca arunca exceptii derivate din

System.Exception.

Exemplu:

using System; public class MyClass {} public class ArgExceptionExample { public static void Main() {

MyClass my = new MyClass(); string s = "sometext";

Page 10: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 10

try { int i = s.CompareTo(my); } catch (Exception e) { Console.WriteLine("Error: {0}",e.ToString()); } } }

Rezultatul este:

Error: System.ArgumentException: Object must be of type String.

at System.String.CompareTo(Object value)

at ArgExceptionExample.Main()

Definirea claselor de exceptii

Prin conventie numele unui tip exceptie ar trebui sa se termine cu Exception.

Metodele ar trebui sa-si verifice argumentele inainte de a le folosi.

Clasele din FCL ce pot fi folosite pentru acest lucru sunt:

• ArgumentNullException,

• ArgumentOutOfRangeException

• DuplicateWaitObjectException.

Nu se va scrie cod ce va arunca o exceptie de tipul Exception,

ApplicationException, sau SystemException.

Exemplu:

class SomeType {

public void SomeMethod(Object o) {

if (!((o is ICloneable) && (o is IComparable))) throw new LipsaInterfataException(...); // urmeaza cod

} }

Aici avem tipul LipsaInterfataException. Cum il definim?

Singura regula de care trebuie sa tinem seama este cea referitoare la efectele colaterale.

Daca derivam aceasta exceptie din ArgumentException, atunci codul existent ce

capteaza aceasta exceptie va capta si noua exceptie.

Cand definim acest tip trebuie sa vedem cu cine se aseamana dintre exceptiile existente,

asemanare in sensul metodei de tratare a exceptiei.

Page 11: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 11

Daca derivam tipul din Exception nu exista prea multe informatii despre exceptia

aruncata.

Cel mai indicat este sa ne gandim la efectele colaterale decat la cele directe cand derivam

un tip exceptie.

Clasa de baza Exception defineste trei constructori:

1. unul implicit ce seteaza toate campurile si proprietatile la valori implicite;

2. un ctor cu un parametru de tip String ce creaza o instanta a tipului si seteaza un

mesaj specific.

3. un ctor cu doi parametri: un String si o instanta a unui tip derivat din

Exception ce seteaza un mesaj si o exceptie interna.

Daca adaugam campuri la un tip exceptie acestia trebuiesc initializati in constructor.

Exemplu

Generarea si tratarea unei exceptii ce face referinta la “inner Exception”.

using System; public class MyAppException: ApplicationException { public MyAppException (String message) : base (message) {} public MyAppException (String message, Exception inner) : base(message,inner) {} }

public class ExceptExample {

public void ThrowInner () { throw new MyAppException("ExceptExample inner exception"); } public void CatchInner() { try { this.ThrowInner(); } catch (Exception e) { throw new MyAppException("Error caused by trying ThrowInner.",e); }

} } public class Test { public static void Main() { ExceptExample testInstance = new ExceptExample();

Page 12: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 12

try { testInstance.CatchInner(); } catch(Exception e) { Console.WriteLine ("In Main catch block. Caught: {0}", e.Message); Console.WriteLine ("Inner Exception is {0}",e.InnerException); }

} }

Rezultatul este: In Main catch block. Caught: Error caused by trying ThrowInner.

Inner Exception is MyAppException: ExceptExample inner exception

at ExceptExample.ThrowInner()

at ExceptExample.CatchInner()

Exemplu (2) de definire a unei exceptii :

using System; using System.IO; public class CustomException : ApplicationException { object extraInfo;

public CustomException(string message, object extra) : base(message)

{ extraInfo = extra; } public override string ToString() { return "CustomException: " + extraInfo.ToString() + "" + base.Message + "" + base.StackTrace; } } // Test class CustomExceptionGenerator { static void Main() { try { Metoda(); }

Page 13: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 13

catch (CustomException ce) { Console.WriteLine(ce.ToString()); } Console.ReadLine(); } public static void Metoda() { // Daca aici adaugam urmatorul cod: //

// int i, j,k ; // i = 10 ; // j = 0 ; // k = i/j ; // // atunci apare « Unhandled Exception » // si apoi exceptia creata.

// throw new CustomException("Ceva e gresit aici...", "ExtraInfo");

} }

Rezultatul este :

CustomException: ExtraInfo

Ceva e gresit aici ...

at CustomExceptionGenerator.SomeMethod() in c:\Documents and Settings\info\My

Documents\SharpDevelop Projects\p5_exception1\Main.cs:line 49

at CustomExceptionGenerator.Main() in c:\Documents and Settings\info\My Docum

ents\SharpDevelop Projects\p5_exception1\Main.cs:line 36

Page 14: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 14

Garbage Collection

Probleme:

� Creare obiecte.

� Gestiune memorie heap.

� Eliberare memorie heap (distrugere obiecte).

Etapele necesare pentru a accesa o resursa:

1. Creare resursa (operatorul new). 2. Initializare memorie pentru a seta starea initiala a obiectului (operatiile se

realizeaza in constructor).

3. Utilizare resursa prin accesarea membrilor tipului respectiv.

4. Eliberare resursa (eliberarea zonei de memorie ocupata de resursa).

Managementul automat al memoriei incearca sa rezolve problemele legate de accesarea

obiectelor inexistente (bug de programare) precum si mentinerea memoriei heap intr-o

stare consistenta (pierderi de memorie la nivel de aplicatie).

Tipurile preconstruite, cum ar fi Int32, Point, Rectangle, String, ArrayList si

SerializationInfo, reprezinta resurse ce nu au nevoie de cod special pentru a fi eliberate

din memorie.

Tipurile ce reprezinta (sau wrap) resurse unmanaged cum ar fi fisiere, socket-uri,

mutexuri, bitmap, etc., au nevoie de executia unui cod cand obiectul este distrus.

Resursele unmanaged nu sunt gestionate de garbage collector.

Alocare memorie si initializare resurse

Cerinta principala a CLR-ului este ca toate resursele sa fie alocate intr-o memorie heap

numita managead heap. Din aceasta memorie « managed heap », dezvoltatorul nu va

elibera obiectele, acestea vor fi dealocate automat cand aplicatia nu mai are nevoie de ele.

Cand stie managed heap ca un obiect nu mai este necesar in aplicatie si trebuie eliberat?

Exista mai multi algoritmi pentru a realiza acest lucru, fiecare lucrand bine intr-un anumit

mediu.

Cand un proces este initializat, CLR rezerva o zona contigua de memorie (adrese) care

initial nu contine nici un obiect. Aceasta zona (heap) este gestionata cu ajutorul unui

pointer, numit in cazul de fata, NextObjPtr.

Acest pointer indica adresa urmatorului bloc liber in heap, deci unde se va aloca

urmatorul obiect nou creat.

Initial, NextObjPtr contine adresa de inceput a zonei rezervate pentru heap.

Page 15: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 15

Operatorul new este folosit pentru alocarea unui obiect in heap, iar in IL (limbaj

intermediar) ii corespunde instructiunea newobj.

CLR-ul executa urmatorele lucruri cand se creaza un nou obiect:

1. Calculeaza numarul de octeti necesari pentru noul tip si toate tipurile sale de

baza ;

2. Fiecare obiect mentine doua campuri speciale (32 biti lungime): un camp ce

mentine un pointer la o tabela de pointeri la metode si un SyncBlockIndex. Pe

un sistem pe 32 biti se mai adauga in plus 8 octeti pentru fiecare obiect, iar pe un

sistem 64-biti se adauga 16 octeti pentru fiecare obiect.

3. Verifica daca exista memorie suficienta in heap. Daca exista memorie, obiectul

este alocat la adresa data de NextObjPtr.

4. Se apeleaza constructorul obiectului (valoarea lui this este egala cu valoarea lui

NextObjPtr) si se obtine adresa unde este memorat obiectul (pointerul this).

5. Se modifica valoarea lui NextObjPtr, astfel incat acesta sa puncteze la

urmatoarea zona de memorie, libera.

Dupa cum se observa din figura, intre obiecte nu exista spatiu de memorie nefolosit. Una

din caracteristicile « managed heap » este si aceasta de a memora obiectele unul dupa

altul fara zone libere de memorie intre obiecte (zona contigua de obiecte). Din punctul de

vedere al « memoriei gestionate » (managed heap) aceasta presupune ca spatiul de adrese

de memorare este infinit. Din cauza ca acest lucru nu este posibil, s-a implementat un

mecanism, ce tine sub control aceasta presupunere, numit : garbage collector (GC).

In principiu acest mecanism asigura intretinerea zonei heap astfel incat obiectele ce nu

mai sunt necesare aplicatiei sunt eliminate si memoria este compactata.

Ideea generala pentru GC : este apelat in momentul cand se cere alocarea unui nou obiect

in heap managed si nu mai exista loc in heap. In realitate mecanismul este foarte

sofisticat si supus mereu schimbarii. Acesta poate fi implementat ca un fir de executie ce

se executa in background, fir ce are o prioritate scazuta. Prioritatea firului poate creste in

momentele critice, cand este absolut necesara compactarea memoriei. Obiectele din heap

au asociate anumite atribute folosite de algoritmul implementat in GC. De exemplu

obiectele sunt impartite in « clase » (generatii) pentru a face diferenta intre obiectele

vechi si cele noi. De asemenea obiectele pastreaza o stare ce poate indica faptul ca

acestea nu mai sunt necesare (ar fi trebuit sa se execute destructorul) dar ele inca persista

in aceasta zona.

Page 16: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 16

Algoritmul Garbage Collection. Idee generala.

GC verifica daca exista in heap obiecte ce nu mai sunt utilizate de aplicatie, iar in caz

afirmativ obiectele sunt eliberate si memoria compactata. In cazul cand nu mai exista

memorie heap disponibila se genereaza exceptia OutOfMemoryException.

Fiecare aplicatie are o multime de “radacini” (puncte de intrare) in heap. Un punct de

intrare contine un pointer la un tip referinta.

Acest pointer poate referi un obiect din heap sau poate fi null.

Toate variabilele globale si locale, variabilele statice, de tip referinta sunt

considerate puncte de intrare (radacini) in heap, de asemenea variabilele parametru de tip

referinta de pe stiva unui fir sunt considerate puncte de intrare in heap.

In interiorul unei metode, un registru CPU ce se refera la un obiect de tip

referinta, este considerat punct de intrare.

Compilatorul JIT creaza tabele interne in momentul cand compileaza o metoda

(cod IL), iar punctele de intrare in aceste tabele contin adrese sau registri CPU si

constituie puncte de intrare in heap.

Folosind aceste tabele si alte informatii pentru obiectele din heap, GC poate

determina daca o anumita zona din heap contine un obiect valid sau nu. De asemenea GC

are acces la stiva firului si o poate examina pentru a determina daca exista metode ce fac

referire la obiecte din heap.

GC presupune ca toate obiectele din heap sunt invalide (adica trebuiesc eliminate).

Se construieste un graf al tuturor punctelor de intrare in heap pentru obiectele valide.

Ceea ce nu se gaseste in acest graf se considera ca sunt obiecte ce trebuiesc eliminate. In

continuare GC parcurge liniar memoria heap si va elimina obiectele ce nu sunt in graf

(algoritmul prezentat este foarte simplificat) compactand in acelasi timp memoria heap.

Compactarea memoriei heap de catre GC are ca efect modificarea tabelei ce contine

puncte de intrare in heap, in caz contrar am avea referinte la obiecte ce nu mai sunt la

adresa corecta (daca un obiect contine un pointer la alt obiect se va modifica si valoarea

acestui pointer). In final NextObjPtr va puncta la prima zona de meorie libera

(memorie organizata in mod liniar).

Din punctul de vedere al programatorului, exista anumite avantaje. Acesta nu mai trebuie

sa scrie cod pentru a gestiona timpul de viata al obiectului.

Page 17: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 17

Urmatorul cod (MSDN) arata cum sunt alocate si gestionate obiectele in heap.

class App { static void Main() {

// ArrayList object created in heap, a is now a root. ArrayList a = new ArrayList(); // Create 10000 objects in the heap. for (Int32 x = 0; x < 10000; x++) {

a.Add(new Object()); // Object created in heap } // Right now, a is a root (on the thread’s stack). So a is // reachable and the 10000 objects it refers to are reachable. Console.WriteLine(a.Length); // After a.Length returns, a isn’t referred to in the code // and is no longer a root. // If another thread were to start a garbage collection // before the result of a.Length were passed to WriteLine, // the 10000 objects would have their memory reclaimed. Console.WriteLine("End of method"); }

}

CLR foloseste metadata pentru a determina membrii unui obiect ce se refera la alte

obiecte.

Finalizare

Orice tip ce incapsuleaza (wrap) o resursa negestionata (unmanaged), cum ar fi fisier,

obiect nucleu mutex, socket, etc., trebuie sa suporte finalizarea, adica sa ofere resursei

eliberarea corecta cand aceasta va fi supusa procesului de colectare in vederea eliminarii

(garbage collection).

Pentru aceasta tipul implementeaza o metoda numita Finalize.

Cand GC determina ca un obiect trebuie eliminat din memorie, acesta apeleaza metoda

Finalize a obiectului, daca aceasta exista - in sensul ca fost scris cod pentru aceasta

metoda.

Observatie

Metoda Finalize() este definita in clasa Object astfel: protected virtual void Finalize().

Page 18: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 18

In metoda Finalize se va apela metoda corespunzatoare pentru “eliberarea resursei”,

pentru fisiere sau obiecte nucleu ( de exemplu aceasta metoda poate avea numele

CloseHandle).

Pentru tipurile ce folosesc resurse unmanaged este obligatoriu de a defini aceasta metoda

Finalize, in caz contrar resursa nu este eliberata corect din memorie, si vor exista

“pierderi” de memorie ce vor fi rezolvate de catre SO la terminarea procesului (vezi ceva

asemanator la obiecte nucleu).

In MSDN

The Finalize method is used to perform cleanup operations on unmanaged resources held by the current object before the current object is destroyed. The method is protected and therefore

is accessible only through this class or through a derived class.

This method is automatically called after an object becomes inaccessible, unless the object has

been exempted from finalization by a call to GC.SuppressFinalize. During shutdown of an

application domain, Finalize is automatically called on objects that are not exempt from

finalization, even those that are still accessible. Finalize is automatically called only once on a given instance, unless the object is re-registered using a mechanism such

as GC.ReRegisterForFinalize and GC.SuppressFinalize has not been subsequently called.

Every implementation of Finalize in a derived type must call its base type's implementation

of Finalize. This is the only case in which application code is allowed to call Finalize.

Urmatoarul exemplu (pseudo cod) arata cum ar trebui scris codul din metoda Finalize.

Acesta cod nu se compileaza. In realitate nu putem scrie o asemenea metoda in C#.

public sealed class OSHandle {

// Acest camp pastreaza un handle Win32 la resursa unmanaged. private IntPtr handle; // Ctor initializeaza handle. public OSHandle(IntPtr handle) {

this.handle = handle; } // Metoda Finalize apelata de GC in momentul cand // se cere eleiberarea memoriei folosite de obiect.

protected override void Finalize() {

try {

CloseHandle(handle); } catch() { Console.WriteLine(“Nu putem elibera resursa!!!”);

Page 19: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 19

} finally {

base.Finalize(); }

}

public IntPtr ToHandle() {

return handle; }

[System.Runtime.InteropServices.DllImport("Kernel32")] private extern static Boolean CloseHandle(IntPtr handle);

}

Explicatii :

Cand obiectul OSHandle este supus procesului de curatare (obiectul in acest moment nu

mai este valid pentru aplicatie, dar pentru GC este inca valid), GC va apela metoda

Finalize a acestui obiect.

In blocul finally se apeleaza metoda de baza Finalize, adica cea din System.Object,

aceasta asigurand ca acest cod se va executa chiar daca a aparut o exceptie (nu in CLR !).

Pentru a inlatura eventualele codari eronate in metoda Finalize (netratarea exceptiilor

si neapelarea metodei System.Object.Finalize) s-a definit o sintaxa speciala pentru

aceasta metoda. Sintaxa pentru destructor.

Sa urmarim codul urmator care este aproape identic cu cel anterior.

public sealed class OSHandle {

private IntPtr handle; public OSHandle(IntPtr handle) {

this.handle = handle; }

// Metoda Finalize apelata de GC in momentul cand // se cere eleiberarea memoriei folosite de obiect. ~OSHandle() {

CloseHandle(handle); }

// cod ...

[System.Runtime.InteropServices.DllImport("Kernel32")] private extern static Boolean CloseHandle(IntPtr handle);

}

Page 20: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 20

Observatii

Aici apare o confuzie in utilizarea acestui destructor pentru OSHandle.

Daca se examineaza codul IL, atunci acesta apare ca cel descris in primul exemplu.

Explicatie cod :

Pentru a crea o instanta a obiectului OSHandle, vom apela o functie Win32 ce returneaza

un handle la o resursa unmanaged, de ex. CreateFile, CreateMutex,

CreateSemaphore, CreateEvent, etc. Apoi folosim operatorul new din C# pentru a

construi o instanta pentru OSHandle, pasand ca parametru in ctor acest handle. Cand

acest obiect va fi tratat de GC, GC va « vedea » ca exista o metoda Finalize

implementata si o va apela, ceea ce va permite eliberarea resursei nucleu (vezi si

gestionarea timpului de viata al unui obiect nucleu, se va apela CloseHandle()).

CLR nu suporta distrugerea determinista ( !) a unui obiect (nu putem scrie cod pentru a

distruge obiectul). Finalize va fi apelata numai de GC, iar cand GC se executa nu stim

si nu putem programa acest lucru.

Nu se recomanda folosirea metodei Finalize cand se dezvolta un tip. Timpul procesor

pentru GC va creste caci trebuie sa apeleze Finalize pe obiectele pe care le va distruge

si pe toate obiectele la care face referire un alt obiect ce are metoda Finalize

implementata.

De exemplu, pentru un tablou cu 10000 de obiecte pe fiecare obiect se va apela metoda

Finalize cand acesta va fi in atentia GC.

Pentru resursele unmanaged este obligatorie folosirea metodei Finalize.

Intern se construieste o lista cu obiectele ce implementeaza metoda Finalize. GC va

trebui sa consulte si aceasta lista.

Observatie :

Nu trebuie scris cod in Finalize ce acceseaza obiecte interne ale obiectului curent,

membri pentru asemenea obiecte.

De exemplu avem un obiect, numit Extern, ce contine un pointer (referinta) la un alt

obiect, numit Intern. Deoarece GC nu apeleaza intr-o ordine determinista metoda

Finalize, este posibil sa se apeleze Finalize pe obiectul Intern in timp ce obiectul

extern este in « viata ». Nu avem nici un control asupra ordinii executiei metodelor

Finalize.

In acest moment pointerul (referinta) din obiectul Extern la obiectul Intern este invalid.

Codul din Finalize trebuie sa se execute foarte rapid (asemanator ca la sectiuni critice).

Page 21: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 21

Eliberarea acestor obiecte se face cu metoda Dispose().

1. Nu trebuie scris cod pentru sincronizare in cadrul acestei metode.

2. In Finalize trebuiesc tratate exceptiile.

3. In Finalize nu trebuie sa facem referire la obiecte managed sau metode statice

managed, este posibil ca aceste obiecte sa nu mai existe sau metodele statice sa

faca referire la obiecte ce nu mai exista.

Urmatorul exemplu (Tom Archer : Inside C#...) emite un sunet cand GC executa o

colectie.

public sealed class GCBeep {

~GCBeep() {

// We’re being finalized, beep.

MessageBeep(-1);

// If the AppDomain isn’t unloading, // create a new object // that will get finalized at the next collection.

if (!AppDomain.CurrentDomain.IsFinalizingForUnload())

new GCBeep(); }

[System.Runtime.InteropServices.DllImport("User32.dll")] private extern static Boolean MessageBeep(Int32 uType);

}

class TestApp {

static void Main() {

// Constructing a single GCBeep object causes // a beep to occur every time a // garbage collection starts. new GCBeep();

// Construct a lot of 100-byte objects.

for (Int32 x = 0; x < 10000; x++) {

Console.WriteLine(x); Byte[] b = new Byte[100];

} }

}

Page 22: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 22

Cauzele ce produc apelul metodei Finalize

1. Generatia 0 este plina. Acest eveniment este calea cea mai obisnuita de a apela

metoda Finalize, pentru ca acesta apare cand aplicatia se executa si are nevoie

sa aloce noi obiecte.

2. Codul apeleaza explicit metoda statica Collect din System.GC. Codul poate

cere in mod explicit CLR-ului sa execute o colectie. MS nu recomanda apelul

acestei metode.

3. CLR descarca un AppDomain. Cand se intimpla acest lucru, CLR considera ca

nu exista intrari in heap in cadrul AppDomain si apeleaza Finalize pentru

obiectele ce au fost create in AppDomain.

4. CLR se inchide (shuting down). Cand un proces se termina OK, se incearca

terminarea corecta a CLR-ului. In acest moment CLR considera ca nu exista

puncte de intrare in heap in cadrul procesului si apeleaza metoda Finalize

pentru obiectele din heap managed.

CLR foloseste un fir dedicat pentru a apela metodele Finalize. Pentru primele trei

evenimente metoda Finalize intra intr-o bucla infinita, firul este blocat si nu se mai

apeleaza nici o metoda Finalize. Este un dezastru.

Pentru evenimentul 4, fiecare metoda Finalize consuma aproximativ 2 secunde pentru

executie. Daca nu se intimpla asa, CLR omoara procesul si nu se mai apeleaza alte

metode Finalize. De asemenea, daca CLR consuma mai mult de 40 secunde pentru a

apela o metoda Finalize a unui obiect, CLR omoara procesul.

Valorile scrise mai sus pot fi schimbate de MS in cadrul procesului de imbunatatire al

algoritmului pentru GC.

Codul din Finalize poate construi alte obiecte; daca se intimpla asta in timp ce CLR se

termina (shutdown) CLR va continua sa colecteze obiecte si sa apeleze metodele lor

Finalize pina cand nu mai exista nici un obiect sau au trecut 40 de secunde.

Reluam exemplul GCBeep. Explicatie.

Daca un obiect GCBeep este pe cale sa se finalizeze din cauza evenimentului 1 sau 2, un

nou obiect GCBeep este construit. Este corect pentru ca aplicatia continua sa ruleze,

presupunind ca vor fi mai multe colectii in viitor.

Daca un obiect GCBeep este pe cale sa se finalizeze din cauza evenimentului 3 sau 4, un

nou obiect nu va putea fi construit pentru ca acest obiect ar trebui sa fie creat in timp ce

se descarca AppDomain sau CLR a fost oprit. Daca aceste noi obiecte au fost create,

CLR ar trebui sa poata apela Finalize pentru aceste obiecte.

Pentru a preveni constructia acestor noi obiecte GCBeep, metoda Finalize din GCBeep

apeleaza metoda AppDomain.IsFinalizingForUnload. Aceasta metoda returneaza

TRUE daca metoda Finalize a obiectului este apelata pentru ca AppDomain se

descarca din memorie. Solutia de mai sus este buna numai pentru AppDomain.

Page 23: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 23

Pentru CLR, MS a adaugat proprietatea read-only HasShutdownStarted la clasa

System.Environment.

Metoda Finalize din GCBeep ar trebui sa citeasca aceasta proprietate si daca este TRUE

sa nu mai permita crearea de noi obiecte GCBeep.

Finalizare – probleme interne

Sa ne reamintim ca obiectele ce au implementata metoda Finalize sunt pastrate intr-o

lista separata, lista de finalizare, gestionata de GC.

Obiectele ce nu implementeaza propria metoda Finalize nu sunt trecute in lista de

finalizare, chiar daca sunt derivate din System.Object ce are metoda Finalize.

Sunt doua actiuni importante ce trebuiesc facute : alocare memorie pentru obiectul creat,

inscrierea obiectului in aceasta lista. In fapt se considera actiuni elementare care fiecare la

rindul ei este critica. Putem distinge astfel de operatii: alocare memorie, completare lista

finalizare, construire obiect (apelare constructor).

Ordinea acestor operatii (conform documentatiei MS) este : alocare memorie, completare

lista finalizare, apelare constructor.

Daca obiectul nu este construit din diverse motive, atunci sistemul trebuie sa fie capabil

sa faca rollback pe operatiile anterioare. Cel mai important este eliminarea obiectului din

lista de finalizare. In rest ramane treaba GC sa rezolve problema cu memoria alocata si

nefolosita.

Sa consideram exemplul din figura de mai sus.

Page 24: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 24

Cand se executa GC, obiectele B, E, G, H, I, si J nu mai constituie puncte valide de

intrare in heap (radacini) si deci vor fi supuse procesului de colectare si eliminare.

Pentru fiecare obiect se cauta daca exista in lista de finalizare, iar in caz afirmativ este

eliminata intrarea din aceasta lista si trecuta intr-o alta lista F-reachable si asta inseamna

ca pentru obiectele de aici se va apela metoda Finalize.

Dupa colectie managed heap arata astfel :

Un fir dedicat din CLR, va apela metodele Finalize.

Un fir dedicat este folosit pentru a preveni eventualele probleme legate de sincronizare.

Cand coada F este vida, acest fir este in asteptare. El va fi lansat numai pe evenimente ce

spun ca sunt obiecte in coada F.

Obiectele ce au intrari in coada F nu sunt supuse procesului de eliminare, ele constituie

inca radacini valide pentru heap managed.

Memoria heap managed dupa etapa a doua a colectarii si eliminarii arata astfel:

Page 25: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 25

Clasa GC

public static class GC

Metodele din aceasta clasa influenteaza modul cum este eliberat un obiect managed din

memoria heap.

GC nu recunoaste referinte la un obiect din cod unmanaged.

Metode (MSDN)

Name Description

Collect () Forces an immediate garbage collection of all

generations.

Collect(Int32) Forces an immediate garbage collection from

generation zero through a specified generation.

Collect(Int32, GCCollectionMode)

Forces a garbage collection from generation zero

through a specified generation, at a time specified

by a GCCollectionMode value.

GetGeneration(Object) Returns the current generation number of the

specified object.

GetTotalMemory

Retrieves the number of bytes currently thought

to be allocated. A parameter indicates whether

this method can wait a short interval before

returning, to allow the system to collect garbage

and finalize objects.

KeepAlive

References the specified object, which makes it

ineligible for garbage collection from the start of

the current routine to the point where this method

is called.

ReRegisterForFinalize Requests that the system call the finalizer for the

specified object for which SuppressFinalize has

previously been called.

SuppressFinalize Requests that the system not call the finalizer for

the specified object.

WaitForFullGCComplete(Int32)

Returns, in a specified time-out period, the status

of a registered notification for determining

whether a full garbage collection by common

language the runtime has completed.

WaitForPendingFinalizers Suspends the current thread until the thread that

is processing the queue of finalizers has emptied

that queue.

Page 26: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 26

Proprietati

Name Description

MaxGeneration Gets the maximum number of generations that the system currently

supports.

Paternul Dispose: Fortarea unui obiect sa se stearga

Interfata IDisposable

Metoda Finalize se foloseste in special pentru resurse unmanaged.

Metoda nu poate fi apelata direct.

Tipurile ce ofera posibilitatea de a fi in mod determinist “dispose” sau inchise

implementeaza ceea ce se numeste “dispose pattern”.

Pattern-ul Dispose – defineste conventiile la care un dezvoltator ar trebui sa adere in

momentul cand defineste un tip ce doreste sa poata fi sters in mod implicit.

Pentru un tip ce implementeaza pattern-ul dispose, utilizatorul va putea elimina obiectul

exact atunci cand nu mai are nevoie de el.

Un tip poate contine atat Finalize cat si Dispose de exemplu : clasa

System.IO.BinaryWriter intra in aceasta categorie.

Exemplu (MSDN):

Crearea unei clase ce implementeaza interfata IDisposable si metoda

IDisposable.Dispose. Trebuie eliberata o resursa unmanaged.

using System; using System.ComponentModel; // The following example demonstrates how to create // a resource class that implements the IDisposable interface // and the IDisposable.Dispose method. public class DisposeExample { // A base class that implements IDisposable. // By implementing IDisposable, you are announcing that // instances of this type allocate scarce resources. public class MyResource: IDisposable { // Pointer to an external unmanaged resource. private IntPtr handle; // Other managed resource this class uses. private Component component = new Component();

Page 27: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 27

// Track whether Dispose has been called. private bool disposed = false; // The class constructor. public MyResource(IntPtr handle) { this.handle = handle; }

// Implement IDisposable. // Do not make this method virtual. // A derived class should not be able to override this method. public void Dispose() { Dispose(true); // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SupressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); } // Dispose(bool disposing) executes in two distinct scenarios. // 1. // If disposing equals true, the method has been // called directly or indirectly by a user's code. // Managed and unmanaged resources can be disposed. // 2. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should // not reference other objects. // Only unmanaged resources can be disposed.

private void Dispose(bool disposing) { // Check to see if Dispose has already been called. if(!this.disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if(disposing) { // Dispose managed resources. component.Dispose(); } // Call the appropriate methods to clean up // unmanaged resources here. // If disposing is false, // only the following code is executed. CloseHandle(handle); handle = IntPtr.Zero; // Note disposing has been done. disposed = true;

Page 28: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 28

} }

// Use interop to call the method necessary // to clean up the unmanaged resource. [System.Runtime.InteropServices.DllImport("Kernel32")] private extern static Boolean CloseHandle(IntPtr handle);

// Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method // does not get called. // It gives your base class the opportunity to finalize. // Do not provide destructors in types derived from this class. ~MyResource() { // Do not re-create Dispose clean-up code here. // Calling Dispose(false) is optimal in terms of // readability and maintainability. Dispose(false); } } public static void Main() { // Insert code here to create // and use the MyResource object. } }

Exemplu din MSDN.

In acest caz nu avem de a face cu o resursa unmanaged.

using System; using System.IO; // This class shows how to use a disposable resource. // The resource is first initialized and passed to // the constructor, but it could also be // initialized in the constructor. // The lifetime of the resource does not // exceed the lifetime of this instance. // This type does not need a finalizer because it does not // directly create a native resource like a file handle // or memory in the unmanaged heap. public class DisposableResource : IDisposable { private Stream _resource; private bool _disposed;

Page 29: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 29

// The stream passed to the constructor // must be readable and not null. public DisposableResource(Stream stream) { if (stream == null) throw new ArgumentNullException("Stream in null."); if (!stream.CanRead) throw new ArgumentException( "Stream must be readable."); _resource = stream; _disposed = false; } // Demonstrates using the resource. // It must not be already disposed. public void DoSomethingWithResource() { if (_disposed) throw new ObjectDisposedException( "Resource was disposed."); // Show the number of bytes. int numBytes = (int) _resource.Length; Console.WriteLine("Number of bytes: {0}", numBytes.ToString()); } public void Dispose() { Dispose(true); // Use SupressFinalize in case a subclass // of this type implements a finalizer. GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // If you need thread safety, use a lock around these // operations, as well as in your methods // that use the resource. if (!_disposed) { if (disposing) { if (_resource != null) _resource.Dispose(); Console.WriteLine("Object disposed."); } // Indicate that the instance has been disposed.

Page 30: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 30

_resource = null; _disposed = true; } } } class Program { static void Main() { try { // Initialize a Stream resource to pass // to the DisposableResource class. Console.Write("Enter filename and its path: "); string fileSpec = Console.ReadLine(); FileStream fs = File.OpenRead(fileSpec); DisposableResource TestObj = new DisposableResource(fs); // Use the resource. TestObj.DoSomethingWithResource(); // Dispose the resource. TestObj.Dispose(); } catch (FileNotFoundException e) { Console.WriteLine(e.Message); } } }

Page 31: Exceptii. Garbage Collection. Automatic Memory Management ...iasimin/csharp/C4_Exceptii_GarbageCollector.pdf• Exceptii sistem. Clasa Exception. ... refera la un obiect derivat din

Exceptii

Facultatea de Informatica Iasi – Universitatea Al I. Cuza – Iasi 03.11.2014

Ioan Asiminoaei 31

Folosirea instructiunii using

Exemplu

using System; using System.IO; class App {

static void Main() {

// Create the bytes to write to the temporary file. Byte[] bytesToWrite = new Byte[] { 1, 2, 3, 4, 5 }; // Create the temporary file. using (FileStream fs = new FileStream("Temp.dat", FileMode.Create)) {

// Write the bytes to the temporary file. fs.Write(bytesToWrite, 0, bytesToWrite.Length);

} // Delete the temporary file. File.Delete("Temp.dat"); // This always works now.

} }

In using se initializeaza obiectul si se salveaza o referinta la acesta intr-o variabila. Cu

aceasta referinta apelam metode din obiect.

La intilnirea instructiunii using, compilatorul construieste blocurile try si finally, iar in

blocul finally se face cast la IDisposable pentru a apela metoda Dispose.

Instructiunea using lucreaza numai cu tipuri ce implementeaza interfata IDisposable.