Programování

Osvědčené postupy při používání Dispose a Finalizace v .Net

Microsoft .Net Framework poskytuje garbage collector, který běží na pozadí a uvolňuje paměť obsazenou spravovanými objekty, když na ně již ve vašem kódu neodkazuje. Ačkoli je garbage collector zběhlý v čištění paměti obsazené spravovanými objekty, není zaručeno, že paměť obsazená nespravovanými objekty by byla vyčištěna při spuštění dalšího cyklu GC. Pokud máte ve své aplikaci nespravované prostředky, měli byste se ujistit, že tyto prostředky uvolníte explicitně, až je budete používat. V tomto článku zdůrazním osvědčené postupy, které byste měli dodržovat při vyčištění prostředků použitých ve vaší aplikaci.

GC používá generace k udržování a správě relativní životnosti objektů, které jsou vytvořeny v paměti. Objekty, které jsou vytvořeny nové, jsou umístěny v generaci 0. Základním předpokladem je, že nově vytvořený objekt může mít kratší životnost, zatímco starý objekt může mít delší životnost. Když objekty, které se nacházejí v generaci 0, nejsou po cyklu GC uvolněny, jsou přesunuty do generace 1. Podobně, pokud objekty sídlící v generaci 1 přežijí vyčištění GC, jsou přesunuty do generace 2. Všimněte si, že GC běží častěji v nižší generace než ve vyšších. Takže objekty, které jsou umístěny v generaci 0, by byly vyčištěny častěji ve srovnání s objekty, které jsou umístěny v generaci 1. Je tedy lepší programovací postup zajistit, abyste používali více místních objektů, které objekty ve vyšším rozsahu, aby se zabránilo přesunutí objektů vyšším generacím.

Všimněte si, že když máte ve své třídě destruktor, modul runtime s ním zachází jako s metodou Finalize (). Protože finalizace je nákladná, měli byste použít destruktory pouze v případě potřeby - když máte ve své třídě nějaké prostředky, které byste potřebovali vyčistit. Když máte ve své třídě finalizátor, objekty těchto tříd se přesunou do finalizační fronty. Pokud jsou objekty dosažitelné, přesunou se do fronty „Freachable“. GC uvolňuje paměť obsazenou objekty, které nejsou dosažitelné. GC pravidelně kontroluje, zda jsou objekty, které se nacházejí ve frontě „Freachable“, dosažitelné. Pokud nejsou dosažitelné, paměť obsazená těmito objekty je uvolněna. Je tedy zřejmé, že objekty, které se nacházejí ve frontě „Freachable“, budou potřebovat více času na to, aby je vyčistil garbage collector. Je špatnou praxí mít prázdné destruktory ve své třídě C #, protože objekty pro takové třídy by byly přesunuty do finalizační fronty a poté do fronty "Freachable", pokud to bude nutné.

Finalizátor je implicitně volán, když je uvolněna paměť obsazená objektem. Není však zaručeno, že finalizátor bude vyvolán GC - může nebo nemusí být volán vůbec. V podstatě finalizátor pracuje v nedeterministickém režimu - běhové prostředí nezaručuje, že by finalizátor vůbec byl vyvolán. Můžete však vynutit zavolání finalizátoru, i když to není vůbec dobrý postup, protože jsou spojeny výkonnostní tresty. Finalizátory by měly být vždy chráněny a měly by být vždy použity pouze k vyčištění spravovaných prostředků. Nikdy byste neměli přidělovat paměť uvnitř finalizátoru, psát kód pro implementaci bezpečnosti vláken nebo vyvolat virtuální metody zevnitř finalizátoru.

Metoda Dispose na druhé straně poskytuje „deterministické vyčištění“ přístup k vyčištění prostředků v .Net. Metoda Dispose by však na rozdíl od finalizátoru měla být volána explicitně. Pokud máte ve třídě definovanou metodu Dispose, měli byste se ujistit, že je volána. Metoda Dispose by tedy měla být explicitně volána kódem klienta. Ale co když zapomenete zavolat metodu Dispose vystavenou třídou, která používá nespravované prostředky? Klienti instance třídy, která implementuje IDisposable rozhraní, by měli explicitně volat metodu Dispose. V takovém případě musíte zavolat Dispose z finalizátoru. Tato strategie automatického deterministického finalizace zajišťuje vyčištění nespravovaných prostředků použitých ve vašem kódu.

Měli byste implementovat IDisposable na každý typ, který má finalizátor. Pokud máte ve své třídě nespravované prostředky, je doporučeno implementovat Dispose i Finalize.

Následující fragment kódu ukazuje, jak můžete implementovat vzor Dispose Finalize v C #.

chráněná virtuální prázdnota Dispose (bool disposing)

        {

pokud (likvidace)

            {

// zapíše kód k vyčištění spravovaných objektů

            }

// zapíše kód k vyčištění nespravovaných objektů a prostředků

        }

Tuto parametrizovanou metodu Dispose lze volat automaticky z destruktoru, jak je ukázáno v fragmentu kódu níže.

~ Zdroje ()

        {

pokud (! zlikvidováno)

            {

disposed = true;

Zlikvidujte (false);

            }

        }

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