Undersøg klasse finalizers
Finalizers (historisk kaldet destructors) bruges til at udføre den nødvendige endelige oprydning, når en klasseforekomst indsamles af affaldsopsamleren (GC). I de fleste tilfælde kan du undgå at skrive en finalizer ved hjælp af System.Runtime.InteropServices.SafeHandle eller afledte klasser til at ombryde et ikke-administreret håndtag.
Nogle ting, du skal være opmærksom på, når du bruger finalizers:
- Finalizers kan ikke defineres i
structtyper. De bruges kun sammen med klasser. - En klasse kan kun have én finalizer.
- Finalizers kan ikke nedarves eller overbelastes.
- Finalizers kan ikke kaldes. De aktiveres automatisk.
- En finalizer tager ikke modifikatorer eller har parametre.
Syntaks for en finalizer
I C#defineres en finalizer ved hjælp af en tilde (~) efterfulgt af klassenavnet. Det kræver ingen parametre og kan ikke kaldes eksplicit.
class Car
{
~Car() // finalizer
{
// cleanup statements...
}
}
En finalizer kan også implementeres som en brødtekstdefinition for udtryk, som vist i følgende eksempel.
public class Destroyer
{
public override string ToString() => GetType().Name;
~Destroyer() => Console.WriteLine($"The {ToString()} finalizer is executing.");
}
Relation mellem affaldsindsamling og finalizers
Affaldsopsamleren i .NET administrerer automatisk allokering og frigivelse af hukommelse for administrerede objekter. Når der ikke længere refereres til et objekt, markerer GC det for samling og genvinder til sidst hukommelsen. Hvis en klasse har en finalizer, kalder GC finalizeren, før objektets hukommelse genkaldes. Finalizer gør det muligt for objektet at frigive alle ikke-administrerede ressourcer, det indeholder.
Afslutningsprocessen omfatter typisk følgende trin:
- Når GC registrerer, at et objekt med en finalizer ikke længere kan nås, flyttes objektet til en afslutningskø.
- Finalizertråden udfører metoden finalizer.
- Når finalizeren er kørt, flyttes objektet til GC's
freachablekø, hvor det er berettiget til affaldsindsamling i den næste GC-cyklus.
Eksempel på en finalizer
public class ResourceHolder
{
// Unmanaged resource
private IntPtr unmanagedResource;
// Constructor
public ResourceHolder()
{
// Allocate unmanaged resource
unmanagedResource = /* allocate resource */;
}
// Finalizer
~ResourceHolder()
{
// Release unmanaged resource
if (unmanagedResource != IntPtr.Zero)
{
// Free the resource
/* free resource */
unmanagedResource = IntPtr.Zero;
}
}
}
Implementer et fjernelsesmønster med en finalizer
Grænseflader som IDisposable og IAsyncDisposable bruges til at frigive ressourcer deterministisk. Metoden Dispose kaldes eksplicit for at frigive ressourcer, mens finalizeren fungerer som et sikkerhedsnet for at sikre, at ressourcerne frigives, selvom Dispose ikke kaldes.
Vigtig
Oprettelse og brug af grænseflader ligger uden for dette moduls område. Brugen af IDisposable er beskrevet her for at give kontekst for "fjernelsesmønsteret". Oplæring, der indeholder en introduktion til grænseflader, er tilgængelig på Microsoft Learn-platformen.
Vær opmærksom på følgende, når du bruger finalizers:
- Finalizers er nondeterministiske, hvilket betyder, at du ikke kan forudsige, hvornår finalizeren kører. Det afhænger af regeringskonferencens tidsplan. Denne funktionsmåde kan medføre forsinkelser i frigivelsen af ikke-administrerede ressourcer.
- Finalizers kan påvirke ydeevnen, fordi det tager længere tid at indsamle objekter med finalizers.
- Implementering af grænsefladen
IDisposableog metodenDisposetil deterministisk oprydning af ressourcer anbefales. MetodenDisposekan kaldes eksplicit for at frigive ressourcer, og finalizeren kan bruges som et sikkerhedsnet.
Her er et eksempel på en klasse, der implementerer grænsefladen IDisposable og en finalizer:
public class ResourceHolder : IDisposable
{
// Unmanaged resource
private IntPtr unmanagedResource;
private bool disposed = false;
// Constructor
public ResourceHolder()
{
// Allocate unmanaged resource
unmanagedResource = /* allocate resource */;
}
// Dispose method
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Free other managed objects
}
// Free unmanaged resources
if (unmanagedResource != IntPtr.Zero)
{
/* free resource */
unmanagedResource = IntPtr.Zero;
}
disposed = true;
}
}
// Finalizer
~ResourceHolder()
{
Dispose(false);
}
}
I dette eksempel:
- Metoden
Disposekaldes for at frigive ressourcer deterministisk. - Finalizer kalder
Dispose(false)for at frigive ikke-administrerede ressourcer, hvisDisposeikke blev kaldt. -
GC.SuppressFinalize(this)bruges til at forhindre, at finalizeren kører, hvisDisposeallerede er blevet kaldt.