Quand devrais-je utiliser GC.SuppressFinalize ()?
-
02-07-2019 - |
Question
Dans .NET, dans quelles circonstances dois-je utiliser GC.SuppressFinalize ()
?
Quels sont les avantages de cette méthode?
La solution
SuppressFinalize ne doit être appelé que par une classe disposant d'un finaliseur. Il informe le collecteur de déchets que cet objet
a été entièrement nettoyé.
Le modèle IDisposable recommandé pour un finaliseur est:
public class MyClass : IDisposable
{
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// called via myClass.Dispose().
// OK to use any private object references
}
// Release unmanaged resources.
// Set large fields to null.
disposed = true;
}
}
public void Dispose() // Implement IDisposable
{
Dispose(true);
GC.SuppressFinalize(this);
}
~MyClass() // the finalizer
{
Dispose(false);
}
}
Normalement, le CLR garde un œil sur les objets avec un finaliseur lors de leur création (ce qui les rend plus coûteux à créer). SuppressFinalize indique au CPG que l'objet a été nettoyé correctement et qu'il n'est pas nécessaire de le placer dans la file d'attente du finaliseur. Cela ressemble à un destructeur C ++, mais n'agit en rien.
L'optimisation SuppressFinalize n'est pas triviale, car vos objets peuvent attendre longtemps dans la file d'attente du finaliseur. Ne soyez pas tenté d'appeler SuppressFinalize sur d'autres objets que vous. C’est un grave défaut qui attend de se produire.
Les directives de conception nous informent qu'un finaliseur n'est pas nécessaire si votre objet implémente IDisposable, mais si vous avez un finaliseur, vous devez implémenter IDisposable pour permettre le nettoyage déterministe de votre classe.
La plupart du temps, vous devriez pouvoir vous en sortir avec IDisposable pour nettoyer les ressources. Vous ne devriez avoir besoin d'un finaliseur que lorsque votre objet contient des ressources non gérées et que vous devez vous assurer que ces ressources sont nettoyées.
Remarque: Parfois, les codeurs ajoutent un finaliseur pour déboguer les versions de leurs propres classes IDisposable afin de vérifier que le code a correctement supprimé leur objet IDisposable.
public void Dispose() // Implement IDisposable
{
Dispose(true);
#if DEBUG
GC.SuppressFinalize(this);
#endif
}
#if DEBUG
~MyClass() // the finalizer
{
Dispose(false);
}
#endif
Autres conseils
vous dites au système que tout le travail qui aurait été fait dans le finaliseur a déjà été fait, de sorte que le finaliseur n'a pas besoin d'être appelé. À partir de la documentation .NET:
Objets qui implémentent l'IDisposable l'interface peut appeler cette méthode de la méthode IDisposable.Dispose à empêcher le ramasse-miettes de appeler Object.Finalize sur un objet qui n'en a pas besoin.
En général, la plupart des méthodes Dispose () devraient pouvoir appeler GC.SupressFinalize (), car elles devraient nettoyer tout ce qui serait nettoyé dans le finaliseur.
SupressFinalize est juste quelque chose qui fournit une optimisation qui permet au système de ne pas se préoccuper de regarder l’objet dans le thread du finaliseur. Un finaliseur / Dispose () correctement écrit doit fonctionner correctement avec ou sans appel à GC.SupressFinalize ().
Cette méthode doit être appelée sur la méthode Dispose des objets qui implémentent IDisposable. Ainsi, le GC n'appellera pas le finaliseur une autre fois si quelqu'un appelle la méthode Dispose.
Voir: http://msdn.microsoft.com /en-us/library/system.gc.suppressfinalize.aspx
Dispose(true);
GC.SuppressFinalize(this);
Si l'objet a un finaliseur, .net place une référence dans la file d'attente de finalisation
Etant donné que nous avons appelé Dispose (ture), c'est un objet vide, nous n'avons donc pas besoin de la file d'attente de finalisation pour effectuer ce travail.
Appelez donc GC.SuppressFinalize (this) supprime la référence dans la file d'attente de finalisation.
Si une classe, ou quelque chose qui en dérive, peut contenir la dernière référence active à un objet avec un finaliseur, alors GC.SuppressFinalize (this)
ou GC.KeepAlive (this )
doit être appelé sur l'objet après toute opération susceptible d'être affectée négativement par ce finaliseur, afin de garantir que le finaliseur ne s'exécutera pas tant que l'opération ne sera pas terminée.
Le coût de GC.KeepAlive ()
et de GC.SuppressFinalize (this)
est essentiellement le même dans toutes les classes ne disposant pas de finaliseur, et les classes qui Les finaliseurs doivent généralement appeler GC.SuppressFinalize (this)
, de sorte que cette dernière fonction constitue la dernière étape de Dispose ()
ne sera peut-être pas toujours nécessaire, mais elle aura été gagnante. ne pas se tromper.