Programmering

Bedste fremgangsmåder til brug af bortskaffelse og afslutning i .Net

Microsoft .Net Framework leverer en affaldssamler, der kører i baggrunden og frigiver hukommelsen optaget af administrerede objekter, når de ikke længere henvises til i din kode. Selvom affaldssamleren er dygtig til at rydde op i hukommelsen, der er optaget af styrede objekter, er det ikke garanteret, at hukommelse, der er besat af ikke-styrede objekter, bliver renset, når den næste GC-cyklus udføres. Hvis du har ikke-administrerede ressourcer i din applikation, skal du sikre dig, at du frigiver sådanne ressourcer eksplicit, når du er færdig med at bruge dem. I denne artikel vil jeg fremhæve de bedste fremgangsmåder, du skal følge for at rydde op i ressourcer, der bruges i din applikation.

GC bruger generationer til at vedligeholde og styre den relative levetid for objekter, der oprettes i hukommelsen. Objekter, der oprettes nye, placeres i generation 0. Den grundlæggende antagelse er, at et nyoprettet objekt kan have en kortere levetid, mens et objekt, der er gammelt, måske har en længere levetid. Når objekter, der er bosiddende i generation 0, ikke genvindes efter en GC-cyklus, flyttes de til generation 1. Hvis objekter, der er bosiddende i generation 1, overlever en GC-oprydning, flyttes de ligeledes til generation 2. Bemærk, at GC kører oftere i lavere generationer, som i de højere. Så objekter, der findes i generation 0, vil blive renset oftere sammenlignet med objekter, der ligger i generation 1. Så det er en bedre programmeringspraksis at sikre, at du bruger flere lokale objekter, som objekter i det højere omfang for at undgå, at objekter flyttes til højere generationer.

Bemærk, at når du har en destruktor i din klasse, behandles runtime den som en Finalize () -metode. Da færdiggørelse er dyr, bør du kun bruge destruktører, hvis det er nødvendigt - når du har nogle ressourcer i din klasse, som du skal rydde op. Når du har en finalizer i din klasse, flyttes objekter fra disse klasser til færdiggørelseskøen. Hvis objekterne kan nås, flyttes de til køen "Freachable". GC genvinder hukommelsen optaget af objekter, der ikke kan nås. Med jævne mellemrum kontrollerer GC, om objekterne, der ligger i køen "Freachable", kan nås. Hvis de ikke kan nås, genvindes hukommelse optaget af disse objekter. Så det er tydeligt, at genstande, der befinder sig i den "Freachable" -kø, har brug for mere tid til at blive ryddet op af affaldssamleren. Det er en dårlig praksis at have tomme destruktører i din C # -klasse, da objekter til sådanne klasser flyttes til finaliseringskøen og derefter til "Freachable" -køen, hvis det er nødvendigt.

En finalizer kaldes implicit, når den hukommelse, der er optaget af objektet, genvindes. En finalizer er dog ikke garanteret at blive kaldt af GC - det kaldes måske eller måske slet ikke. I det væsentlige fungerer en finalizer i en ikke-deterministisk tilstand - runtime garanterer ikke, at en finalizer overhovedet vil blive kaldt. Du kan dog tvinge finalizer til at blive kaldt, selvom det slet ikke er en god praksis, da der er præstationsstraffe forbundet. Færdiggørere skal altid beskyttes og bør altid kun bruges til at rense administrerede ressourcer. Du skal aldrig tildele hukommelse inde i finalizer, skrive kode for at implementere trådsikkerhed eller påberåbe virtuelle metoder fra en finalizer.

Metoden Dispose giver på den anden side en "deterministisk oprydning" tilgang til ressourceoprydning i .Net. Imidlertid skal bortskaffelsesmetoden i modsætning til finaliseringen kaldes eksplicit. Hvis du har en bortskaffelsesmetode defineret i en klasse, skal du sikre dig, at den kaldes. Så bortskaffelsesmetoden skal kaldes eksplicit af klientkoden. Men hvad hvis du glemmer at kalde Dispose-metode eksponeret af en klasse, der bruger ikke-administrerede ressourcer? Klienter af en forekomst af en klasse, der implementerer grænsefladen IDisposable, skal kalde Dispose-metoden eksplicit. I dette tilfælde skal du ringe til Dispose fra finalisatoren. Denne automatiske deterministiske finaliseringsstrategi sikrer, at de ikke-administrerede ressourcer, der bruges i din kode, ryddes op.

Du skal implementere IDisposable på alle typer, der har en finalizer. Det er en anbefalet praksis at implementere både bortskaffelse og færdiggørelse, når du har ikke-administrerede ressourcer i din klasse.

Følgende kodestykke illustrerer, hvordan du kan implementere Dispose Finalize-mønsteret i C #.

beskyttet virtuelt tomrum Bortskaf (bool bortskaffelse)

        {

hvis (bortskaffelse)

            {

// skriv kode til oprydning af administrerede objekter

            }

// skriv kode til oprydning af ikke-administrerede objekter og ressourcer

        }

Denne parametriserede bortskaffelsesmetode kan kaldes automatisk fra destruktoren som vist i kodestykket nedenfor.

~ Ressourcer ()

        {

hvis (! bortskaffet)

            {

disponeret = sand;

Bortskaf (falsk);

            }

        }