Programiranje

Najboljše prakse pri uporabi Odstrani in dokončaj v .Net

Microsoft .Net Framework ponuja zbiralnik smeti, ki deluje v ozadju in sprosti pomnilnik, ki ga zasedajo upravljani predmeti, ko v kodi niso več navedeni. Čeprav je zbiralec smeti vešč pri čiščenju pomnilnika, ki ga zasedajo upravljani predmeti, ni zagotovljeno, da bi se pomnilnik, ki ga zasedajo neupravljani predmeti, očistil, ko se izvede naslednji cikel GC. Če imate v svoji aplikaciji neupravljane vire, poskrbite, da boste takšne vire izrecno sprostili, ko boste končali z njihovo uporabo. V tem članku bom izpostavil najboljše prakse, ki jih morate upoštevati pri čiščenju virov, ki se uporabljajo v vaši aplikaciji.

GC uporablja generacije za vzdrževanje in upravljanje relativne življenjske dobe predmetov, ki so ustvarjeni v pomnilniku. Predmeti, ki se ustvarijo novi, se uvrstijo v generacijo 0. Osnovna predpostavka je, da ima novonastali objekt krajšo življenjsko dobo, medtem ko ima stari objekt daljšo življenjsko dobo. Ko predmeti, ki prebivajo v generaciji 0, po ciklu GC niso povrnjeni, se premaknejo v generacijo 1. Podobno, če predmeti, ki prebivajo v generaciji 1, preživijo čiščenje GC, se premaknejo v generacijo 2. Upoštevajte, da GC v nižje generacije, da v višjih. Torej bi se predmeti, ki se nahajajo v generaciji 0, pogosteje čistili v primerjavi s predmeti, ki se nahajajo v generaciji 1. Boljša praksa programiranja je, da zagotovite, da uporabljate več lokalnih objektov, ki objektijo v višjem obsegu, da se prepreči premikanje višjim generacijam.

Ko imate v svojem razredu destruktor, ga izvajalno okolje obravnava kot metodo Finalize (). Ker je dokončanje drago, uporabite destruktorje le, če je to potrebno - če imate v svojem razredu nekaj virov, ki bi jih morali očistiti. Ko imate v svojem razredu zaključevalnik, se predmeti teh razredov premaknejo v čakalno vrsto za dokončanje. Če so predmeti dosegljivi, se premaknejo v čakalno vrsto »Dosegljivo«. GC povrne pomnilnik, ki ga zasedajo predmeti, ki niso dosegljivi. Občasno GC preveri, ali so predmeti, ki se nahajajo v čakalni vrsti "Freachable", dosegljivi. Če niso dosegljivi, se spomin, ki ga zasedajo ti predmeti, povrne. Torej je očitno, da bi predmeti, ki se nahajajo v čakalni vrsti "Freachable", potrebovali več časa za čiščenje zbiralca smeti. Slaba praksa je imeti prazne destruktorje v razredu C #, saj bi se predmeti za take razrede premaknili v čakalno vrsto za zaključek in nato v čakalno vrsto "Freachable", če bi bilo treba.

Ko se povrne pomnilnik, ki ga zasede objekt, se implicitno prikliče zaključevalnik. Vendar GC zagotovo ne bo poklical finalizatorja - lahko ga ali pa sploh ne. V bistvu zaključevalnik deluje v nedeterminističnem načinu - izvajalno okolje ne zagotavlja, da bi končni klic sploh bil poklican. Lahko pa prisilite klic finalizatorja, čeprav to sploh ni dobra praksa, saj so povezane kazni za uspešnost. Finalizatorji morajo biti vedno zaščiteni in vedno uporabljeni za čiščenje samo upravljanih virov. Nikoli ne smete dodeljevati pomnilnika znotraj zaključevalnika, pisati kode za izvajanje varnosti niti ali priklicati navideznih metod znotraj zaključevalnika.

Metoda Dispose na drugi strani ponuja pristop "determinističnega čiščenja" k čiščenju virov v .Net. Vendar je treba metodo Dispose, za razliko od zaključevalnika, izrecno poklicati. Če imate v razredu določeno metodo Dispose, morate zagotoviti, da je poklicana. Torej, mora metoda odlaganja kliče odjemalca izrecno poklicati. Kaj pa, če pozabite poklicati metodo Dispose, ki jo izpostavi razred, ki uporablja neupravljane vire? Naročniki primerka razreda, ki implementira vmesnik IDisposable, morajo izrecno poklicati metodo Dispose. V tem primeru morate poklicati Dispose znotraj zaključevalnika. Ta samodejna deterministična strategija dokončanja zagotavlja čiščenje neupravljanih virov, uporabljenih v kodi.

IDisposable bi morali implementirati za vse vrste, ki imajo dokončanje. Priporočljiva praksa je, da uporabite Dispose in Finalize, če imate v svojem razredu neupravljane vire.

Naslednji delček kode prikazuje, kako lahko v C # izvedete vzorec Odstrani dokončno.

zaščitena virtualna praznina Dispose (odstranjevanje z bool)

        {

če (odstranjevanje)

            {

// zapišemo kodo za čiščenje upravljanih predmetov

            }

// zapišemo kodo za čiščenje neupravljanih predmetov in virov

        }

To parametrizirano metodo odstranjevanja je mogoče samodejno poklicati iz destruktorja, kot je prikazano v spodnjem delčku kode.

~ Viri ()

        {

če (! odstranjen)

            {

razpoloženo = resnično;

Razpolagati (napačno);

            }

        }