有很多问题要求如何检测IDisposable对象泄漏。似乎答案是"you can't"。
我刚用最琐碎的测试案例检查过,FxCop 10.0没有这样做,带有MSVS2010的ReSharper 4没有这样做。
这对我来说似乎不对,比C中的内存泄漏更糟糕(至少我们已经建立了检测工具)。
我在想:是否有可能使用反射和其他模糊的高级技术,我可以在运行时注入一个检查,在终结器中查看是否已调用Dispose
?
WinDBG + SOS的魔术技巧怎么样?
即使没有现成的工具,我也想知道这在理论上是否可行(我的C#不是很尖锐)。
想法?
注意此问题的标题可能会产生误导。这里真正的问题应该是 IDisposable
对象是否Disposed()
正确。由于我认为这是一个错误,因此由GC处理并不重要。
编辑:解决方案:.NET Memory Profiler完成了这项工作。我们只需要在程序结束时发送几个GC.Collect()
垃圾邮件,以便我们的探查器能够正确获取统计信息。
答案 0 :(得分:12)
你搜索得不够好。有很多.NET内存配置文件可以在程序运行时查看你的程序,并让你知道你的内存使用的位置和方式(以及泄漏的内容)。
我会查看以下任何内容:
Microsoft's CLR Memory Profiler (free)
RedGate ANTS Memory Profiler
JetBrain's DotTrace (includes code profiler as well)
SciTech .NET Memory Profiler
<强>更新强>
SciTech的.NET内存分析器有一个名为“Dispose Tracker”的功能,符合OP要求在其应用程序中仅跟踪Dispose调用的请求。
答案 1 :(得分:3)
你可以通过向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模式。
像这样,例如:
/// <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);
}
}
答案 2 :(得分:2)
虽然@Justin Niessner的推荐有效,但我发现使用完整的剖析器太重了。
我创建了我的家酿解决方案:EyeDisposable。它检测程序集以检测何时未调用Dispose
。