簡體   English   中英

檢測“泄露”的IDisposable對象

[英]Detecting “leaked” IDisposable objects

有很多問題要求如何檢測IDisposable對象泄漏。 似乎答案是“你不能”

我剛剛用最瑣碎的測試用例檢查過,FxCop 10.0沒有這樣做,帶有MSVS2010的ReSharper 4沒有這樣做。

這對我來說似乎不對,比C中的內存泄漏更糟糕(至少我們已經建立了檢測工具)。

我在想:是否有可能使用反射和其他模糊的高級技術,我可以在運行時注入一個檢查,在終結器中查看是否已調用Dispose

WinDBG + SOS的魔術技巧怎么樣?

即使沒有現成的工具,我也想知道這在理論上是否可行(我的C#不是很尖銳)。

想法?

注意這個問題的標題可能會產生誤導。 這里真正的問題應該是IDisposable對象是否已正確使用Disposed() 由於我認為這是一個錯誤,因此由GC處理並不重要。

編輯 :解決方案:.NET Memory Profiler完成工作。 我們只需要在程序結束時垃圾郵件幾個GC.Collect() ,以使我們的探查器能夠正確地獲取統計數據。

你搜索不夠努力。 有很多.NET內存配置文件可以在程序運行時查看你的程序,並讓你知道你的內存使用的位置和方式(以及泄漏的內容)。

我會檢查以下任何一項:

微軟的CLR Memory Profiler(免費)
RedGate ANTS Memory Profiler
JetBrain的DotTrace(包括代碼分析器)
SciTech .NET內存分析器

更新

SciTech的.NET內存分析器具有一個名為“Dispose Tracker”的功能,該功能符合OP的要求,即僅在其應用程序中跟蹤Dispose調用。

你可以通過向IDisposable對象添加Finalizer來實現。 在終結器中,您可以檢查對象是否已被丟棄。 如果尚未處理,您可以斷言,或者將某些內容寫入日志或其他任何內容。

 ~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}".FormatString (this.GetType ().Name));
            }
#endif
            Dispose (false);
 }

您可以將此功能Disposable類 - Disposable - 例如,可以將其用作模板來實現例如Disposable模式。

像這樣,例如:

    /// <summary>
    /// Abstract base class for Disposable types.    
    /// </summary>
    /// <remarks>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).
    /// </remarks>
    public abstract class Disposable : IDisposable
    {
        private bool                    _disposed = false;

        /// <summary>
        /// Releases the managed and unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose (true);
            GC.SuppressFinalize (this);
        }

        /// <summary>
        /// Releases the unmanaged and managed resources.
        /// </summary>
        /// <param name="disposing">When disposing is true, the managed and unmanaged resources are
        /// released.
        /// When disposing is false, only the unmanaged resources are released.</param>
        [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;
            }
        }

        /// <summary>
        /// Override this method and implement functionality to dispose the 
        /// managed resources.
        /// </summary>
        protected abstract void DisposeManagedResources();

        /// <summary>
        /// Override this method if you have to dispose Unmanaged resources.
        /// </summary>
        protected virtual void DisposeUnmanagedResources()
        {
        }

        /// <summary>
        /// Releases unmanaged resources and performs other cleanup operations before the
        /// <see cref="Disposable"/> is reclaimed by garbage collection.
        /// </summary>
        [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}".FormatString (this.GetType ().Name));
            }
#endif
            Dispose (false);
        }
    }

雖然@Justin Niessner的推薦有效,但我發現使用完整的剖析器太重了。

我創建了我的家釀解決方案: EyeDisposable 它檢測程序集以檢測何時未調用Dispose

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM