Programovanie

Osvedčené postupy pri používaní funkcií Dispose a Finalize v .Net

Microsoft .Net Framework poskytuje zberač odpadu, ktorý beží na pozadí a uvoľňuje pamäť obsadenú spravovanými objektmi, keď na ne už vo vašom kóde nie je odkaz. Aj keď je program na odstraňovanie odpadu zbehlý v čistení pamäte obsadenej spravovanými objektmi, nie je zaručené, že pamäť obsadená nespravovanými objektmi bude vyčistená pri ďalšom cykle GC. Ak máte vo svojej aplikácii nespravované prostriedky, mali by ste sa ubezpečiť, že ich po ukončení ich používania výslovne uvoľníte. V tomto článku zdôrazním osvedčené postupy, ktoré by ste mali dodržiavať pri čistení zdrojov použitých vo vašej aplikácii.

GC používa generácie na udržiavanie a správu relatívnej životnosti objektov, ktoré sú vytvorené v pamäti. Objekty, ktoré sú vytvorené nové, sú umiestnené v generácii 0. Základným predpokladom je, že novovytvorený objekt môže mať kratšiu životnosť, zatiaľ čo objekt, ktorý je starý, môže mať dlhšiu životnosť. Keď objekty, ktoré sa nachádzajú v generácii 0, nie sú po cykle GC kultivované, presunú sa do generácie 1. Podobne, ak objekty, ktoré sa nachádzajú v generácii 1, prežijú čistenie GC, presunú sa do generácie 2. Upozorňujeme, že GC sa v nižšie generácie ako vo vyšších. Takže objekty, ktoré sa nachádzajú v generácii 0, by sa čistili častejšie v porovnaní s objektmi, ktoré sa nachádzajú v generácii 1. Je teda lepším programovacím postupom zabezpečiť, aby ste použili viac miestnych objektov, ktoré obsahujú objekty vo vyššom rozsahu, aby ste sa vyhli presunu objektov. vyšším generáciám.

Upozorňujeme, že keď máte vo svojej triede deštruktor, runtime s ním zaobchádza ako s metódou Finalize (). Pretože finalizácia je nákladná, deštruktory by ste mali používať iba v prípade potreby - keď máte vo svojej triede nejaké prostriedky, ktoré by ste potrebovali vyčistiť. Keď máte vo svojej triede finalizátor, objekty týchto tried sa presunú do finalizačného frontu. Ak sú objekty dosiahnuteľné, presunú sa do frontu „Freachable“. GC získava späť pamäť obsadenú objektmi, ktoré nie sú dosiahnuteľné. GC pravidelne kontroluje, či sú objekty, ktoré sa nachádzajú vo fronte „Freachable“, dosiahnuteľné. Ak nie sú dosiahnuteľné, pamäť obsadená týmito objektmi sa získa späť. Je teda zrejmé, že objekty, ktoré sa nachádzajú vo fronte „Freachable“, by potrebovali viac času na to, aby ich vyčistil zberač odpadu. Je zlým zvykom mať vo svojej triede C # prázdne deštruktory, pretože objekty pre tieto triedy by sa presunuli do frontu na finalizáciu a potom do frontu „Freachable“, ak to bude potrebné.

Finalizátor sa implicitne volá, keď sa uvoľní pamäť obsadená objektom. Nie je však zaručené, že finalizátor bude vyvolaný GC - môže sa, ale nemusí, volať vôbec. Finalizátor v zásade funguje v nedeterministickom režime - doba behu nezaručuje, že by sa finalizátor vôbec volal. Môžete však donútiť zavolať finalizátor, aj keď to nie je vôbec dobrý postup, pretože sú spojené výkonnostné tresty. Finalizátory by mali byť vždy chránené a mali by sa vždy používať iba na vyčistenie spravovaných zdrojov. Nikdy by ste nemali alokovať pamäť vo vnútri finalizátora, písať kód na implementáciu bezpečnosti vlákien alebo vyvolávať virtuálne metódy z finalizátora.

Metóda Dispose na druhej strane poskytuje „deterministické čistenie“ prístupu k vyčisteniu zdrojov v .Net. Metóda Dispose by sa však na rozdiel od finalizátora mala volať explicitne. Ak máte v triede definovanú metódu Dispose, mali by ste sa ubezpečiť, že sa volá. Metóda Dispose by teda mala byť volaná explicitne kódom klienta. Ale čo keď zabudnete zavolať metódu Dispose vystavenú triedou, ktorá používa nespravované prostriedky? Klienti inštancie triedy, ktorá implementuje rozhranie IDisposable, by mali metódu Dispose volať explicitne. V takom prípade musíte zavolať Dispose z finalizátora. Táto stratégia automatického deterministického finalizácie zaisťuje vyčistenie nespravovaných zdrojov použitých vo vašom kóde.

Mali by ste implementovať IDisposable na každý typ, ktorý má finalizátor. Ak máte vo svojej triede nespravované zdroje, odporúča sa implementovať Dispose aj Finalize.

Nasledujúci úryvok kódu ilustruje, ako môžete implementovať vzor Dispose Finalize v C #.

chránená virtuálna neplatnosť Dispose (bool disposing)

        {

ak (zlikvidovať)

            {

// napíš kód na vyčistenie spravovaných objektov

            }

// napíš kód na vyčistenie nespravovaných objektov a prostriedkov

        }

Túto parametrizovanú metódu Dispose je možné automaticky volať z deštruktora, ako je uvedené v útržku kódu nižšie.

~ Zdroje ()

        {

ak (! zlikvidovaný)

            {

disposed = true;

Zlikvidujte (nepravdivo);

            }

        }

$config[zx-auto] not found$config[zx-overlay] not found