Détecter les objects identifiables «ayant fui»

Il y a beaucoup de questions à se poser pour savoir comment détecter une fuite d’objects identifiables. Il semble que la réponse est “vous ne pouvez pas” .

Je viens de vérifier avec le scénario de test le plus sortingvial, que FxCop 10.0 ne le fait pas, ReSharper 4 avec MSVS2010 ne le fait pas.

Cela me semble faux, pire que les memory leaks en C (pour lesquelles au moins nous avons mis en place des outils de détection).

Je pensais: est-il possible, en utilisant la reflection et d’autres techniques avancées obscures, que je puisse injecter une vérification au moment de l’exécution, dans le finaliseur pour voir si Dispose a été appelé?

Que diriez-vous des tours de magie avec WinDBG + SOS?

Même s’il n’y a pas d’outils existants pour le faire, j’aimerais savoir si c’est théoriquement possible (mon C # n’est pas très net).

Des idées?

NOTE Le titre de cette question a peut-être été trompeur. La vraie question ici devrait être de savoir si un object IDisposable être IDisposable a été Disposed() correctement . Il n’est pas important d’être disposé par le GC, car j’estime que c’est une erreur.

Edit : Solution: .NET Memory Profiler effectue le travail. Nous avons juste besoin de spammer plusieurs GC.Collect() à la fin du programme pour permettre à notre profileur de récupérer correctement les statistiques.

Vous n’avez pas assez cherché. Il existe de nombreux profileurs de mémoire .NET qui parsingnt votre programme au cours de son exécution et vous permettent de savoir où / comment votre mémoire est utilisée (et ce qui la fuit).

Je voudrais vérifier l’un des éléments suivants:

Microsoft CLR Memory Profiler (gratuit)
RedGate ANTS Memory Profiler
JetTrain DotTrace (inclut également le profileur de code)
SciTech .NET Memory Profiler

Mettre à jour

Le profileur de mémoire .NET de SciTech dispose d’une fonctionnalité appelée «Dispose Tracker» qui répond à la demande de l’OP de suivre uniquement les appels Dispose dans leur application.

vous pouvez le faire en ajoutant un Finalizer à vos objects IDisposable. Dans le finaliseur, vous pouvez vérifier si l’object a été supprimé ou non. Si cela n’a pas été éliminé, vous pouvez l’affirmer, ou écrire quelque chose dans un journal, ou peu importe.

  ~Disposable() { #if DEBUG // In debug-builds, make sure that a warning is displayed when the Disposable object hasn't been // disposed by the programmer. if( _disposed == false ) { System.Diagnostics.Debug.Fail ("There is a disposable object which hasn't been disposed before the finalizer call: {0}".FormatSsortingng (this.GetType ().Name)); } #endif Dispose (false); } 

Vous pouvez factoriser cette fonctionnalité dans une classe de base – Disposable -, par exemple, qui peut être utilisée comme modèle pour implémenter le motif Jetable , par exemple.

Comme ceci, par exemple:

  ///  /// Abstract base class for Disposable types. ///  /// This class makes it easy to correctly implement the Disposable pattern, so if you have a class which should /// be IDisposable, you can inherit from this class and implement the DisposeManagedResources and the /// DisposeUnmanagedResources (if necessary). ///  public abstract class Disposable : IDisposable { private bool _disposed = false; ///  /// Releases the managed and unmanaged resources. ///  public void Dispose() { Dispose (true); GC.SuppressFinalize (this); } ///  /// Releases the unmanaged and managed resources. ///  /// When disposing is true, the managed and unmanaged resources are /// released. /// When disposing is false, only the unmanaged resources are released. [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")] protected void Dispose( bool disposing ) { // We can suppress the CA1063 Message on this method, since we do not want that this method is // virtual. // Users of this class should override DisposeManagedResources and DisposeUnmanagedResources. // By doing so, the Disposable pattern is also implemented correctly. if( _disposed == false ) { if( disposing ) { DisposeManagedResources (); } DisposeUnmanagedResources (); _disposed = true; } } ///  /// Override this method and implement functionality to dispose the /// managed resources. ///  protected abstract void DisposeManagedResources(); ///  /// Override this method if you have to dispose Unmanaged resources. ///  protected virtual void DisposeUnmanagedResources() { } ///  /// Releases unmanaged resources and performs other cleanup operations before the ///  is reclaimed by garbage collection. ///  [System.Diagnostics.CodeAnalysis.SuppressMessage ("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly")] ~Disposable() { #if DEBUG // In debug-builds, make sure that a warning is displayed when the Disposable object hasn't been // disposed by the programmer. if( _disposed == false ) { System.Diagnostics.Debug.Fail ("There is a disposable object which hasn't been disposed before the finalizer call: {0}".FormatSsortingng (this.GetType ().Name)); } #endif Dispose (false); } } 

Bien que la recommandation de @Justin Niessner fonctionne, j’estime que l’utilisation d’un profileur complet est trop lourde.

J’ai créé ma solution maison: EyeDisposable . Il instrumente les assemblages pour détecter quand Dispose n’a pas été appelé.