Programmering

Beste fremgangsmåter for bruk av disponere og fullføre i .Net

Microsoft .Net Framework gir en søppeloppsamler som kjører i bakgrunnen og frigjør minnet okkupert av administrerte objekter når det ikke lenger er referert til det i koden din. Selv om søppeloppsamleren er dyktig til å rydde opp i minnet som er okkupert av administrerte objekter, er det ikke garantert at minne som er okkupert av ikke-administrerte objekter vil bli ryddet opp når neste GC-syklus kjøres. Hvis du har uadministrerte ressurser i applikasjonen din, bør du sørge for at du frigjør slike ressurser eksplisitt når du er ferdig med å bruke dem. I denne artikkelen vil jeg fremheve de beste fremgangsmåtene du bør følge for å rydde opp ressursene som brukes i applikasjonen din.

GC bruker generasjoner for å opprettholde og administrere den relative levetiden til objekter som er opprettet i minnet. Objekter som er skapt nye plasseres i generasjon 0. Den grunnleggende antagelsen er at et nyopprettet objekt kan ha kortere levetid mens et objekt som er gammelt, kan ha lengre levetid. Når objekter som er bosatt i generasjon 0 ikke gjenvinnes etter en GC-syklus, flyttes de til generasjon 1. På samme måte flyttes objektene som bor i generasjon 1 til GC-opprydding til generasjon 2. Merk at GC kjører oftere i lavere generasjoner som i de høyere. Så, objekter som ligger i generasjon 0 vil bli ryddet oftere sammenlignet med objekter som ligger i generasjon 1. Så det er en bedre programmeringspraksis å sikre at du bruker flere lokale objekter som objekter i høyere omfang for å unngå at objekter blir flyttet til høyere generasjoner.

Merk at når du har en destruktør i klassen, behandles kjøretiden som en Finalize () -metode. Ettersom sluttføring er kostbart, bør du bare bruke destruktorer om nødvendig - når du har noen ressurser i klassen du trenger å rydde opp. Når du har en finalizer i klassen, blir objekter fra disse klassene flyttet til sluttkøen. Hvis du kan nå objektene, flyttes de til "Freachable" -køen. GC gjenvinner minnet okkupert av objekter som ikke er tilgjengelige. Med jevne mellomrom sjekker GC om objektene som ligger i "Freachable" -køen er tilgjengelige. Hvis de ikke kan nås, blir minnet okkupert av disse gjenstandene gjenvunnet. Så det er tydelig at gjenstander som ligger i "Freachable" -køen trenger mer tid for å bli ryddet opp av søppeloppsamleren. Det er dårlig å ha tomme destruktører i C # -klassen, ettersom objekter for slike klasser vil bli flyttet til sluttkøen og deretter til "Freachable" -køen hvis det er nødvendig.

En finalizer kalles implisitt når minnet okkupert av objektet blir gjenvunnet. Imidlertid er det ikke garantert at en finalizer blir ringt av GC - det kan eller ikke kan kalles i det hele tatt. I det vesentlige fungerer en finalizer i en ikke-deterministisk modus - kjøretiden garanterer ikke at en finalizer i det hele tatt blir kalt. Du kan imidlertid tvinge finalisten til å bli kalt, selv om det ikke er en god praksis, ettersom det er prestasjonsstraffer forbundet. Avsluttere skal alltid beskyttes og bør alltid brukes til å rydde opp bare administrerte ressurser. Du skal aldri tildele minne i finalizer, skrive kode for å implementere trådsikkerhet eller påkalle virtuelle metoder fra en finalizer.

Dispose-metoden gir derimot en "deterministisk opprydding" -tilnærming mot ressursopprydding i .Net. Imidlertid bør Dispose-metoden i motsetning til finalisatoren kalles eksplisitt. Hvis du har en avhendingsmetode definert i en klasse, bør du sørge for at den blir kalt. Så, Dispose-metoden skal kalles eksplisitt av klientkoden. Men hva om du glemmer å kalle Dispose-metoden eksponert av en klasse som bruker ikke-administrerte ressurser? Klienter av en forekomst av en klasse som implementerer IDisposable-grensesnittet, bør kalle Dispose-metoden eksplisitt. I dette tilfellet må du ringe Dispose from the finalizer. Denne automatiske deterministiske finaliseringsstrategien sikrer at de ikke-administrerte ressursene som brukes i koden din blir ryddet opp.

Du bør implementere IDisposable på alle typer som har en finalizer. Det er en anbefalt praksis å implementere både Kast og fullfør når du har uadministrerte ressurser i klassen.

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

beskyttet virtuelt tomrom Kast (bool disponere)

        {

hvis (avhende)

            {

// skrive kode for å rydde opp administrerte objekter

            }

// skriv kode for å rydde opp ubehandlede objekter og ressurser

        }

Denne parametriserte avhendingsmetoden kan kalles automatisk fra destruktoren som vist i kodebiten nedenfor.

~ Ressurser ()

        {

hvis (! avhendes)

            {

disponert = sant;

Kast (falsk);

            }

        }

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