如果某个类具有包含非托管资源的属性。使用类
时如何确保没有内存泄漏Class A
{
B {get; set;}
}
B包含非托管资源。
答案 0 :(得分:7)
实施IDisposable
并通过调用Dispose()
来清理您的非托管资源,最好将Dispose
的调用放在finally
语句中,以便即使在案例中也可以清理资源例外。
C#有一个using
关键字,您可以使用它来确保调用Dispose
方法,即使抛出异常也是如此。
编辑:根据Ran的答案合并调用GC.SuppressFinalize和终结器实现
class A : IDisposable
{
private bool _disposed;
~A()
{
this.Dispose(false);
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// dispose managed resources
}
// clean up unmanaged resources
_disposed = true;
}
}
}
class Program
{
static void Main(string[] args)
{
using (var someInstance = new A())
{
// do some things with the class.
// once the using block completes, Dispose
// someInstance.Dispose() will automatically
// be called
}
}
}
答案 1 :(得分:4)
使用IDisposable
可能还不够,因为它依赖于用户记住调用Dispose
或使用using
等。
要获得完整的解决方案,请合并IDisposable
和终结器。像这样:
编辑:根据 SpeksETC 的评论在Dispose方法中进行了一些更正。
class MyClass : IDisposable
{
~MyClass()
{
Dispose(false);
}
public void Dispose()
{
GC.SupressFinalize();
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing)
{
// clear unmanaged resources here (can only be called once)
...
}
// dispose called explicitly by the user, clean up managed resources here
...
}
}
这可确保始终清除本机资源,即使用户忘记呼叫Dispose
,同时仍允许用户提前清除资源。
if
实施中的Dispose
是必需的,因为如果要完成此课程,您可能不会在您的成员上致电Dispose
,因为他们可能已经过GC。< / p>
答案 2 :(得分:1)
我认为必须指出B是托管资源,只有包含非托管资源。
因此,A应该在其Dispose()方法中实现IDisposable并处理B,但不需要终结器,因为它没有任何非托管资源来清理 - 终结器需要在B本身内实现。即使你实现了终结器,它也会调用一个看起来像这样的Dispose:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// dispose called explicitly by the user, clean up managed resources here
b.Dispose()
}
// no unmanaged resources to clean up so do nothing which makes Finalizer unneccesary
...
}
答案 3 :(得分:0)
SpeksEtc是正确的,如果B包含非托管资源,那么B应该确保没有泄漏而不是A.
但是什么是非托管资源?SafeHandle类有帮助吗?然后B将包含一个SafeHandle,它将包含非托管资源,您不必担心它。