C# 困惑的CA1063错了吗?GC.1(本)
我有一个简单的类MyDataClass,其中包含一个实现IDisposable的成员(obj):C# 困惑的CA1063错了吗?GC.1(本),c#,.net,garbage-collection,C#,.net,Garbage Collection,我有一个简单的类MyDataClass,其中包含一个实现IDisposable的成员(obj): public class MyDataClass : IDisposable { private DisposableObject obj; private List<string> list; private int c; public MyDataClass() { obj = new DisposableObject();
public class MyDataClass : IDisposable
{
private DisposableObject obj;
private List<string> list;
private int c;
public MyDataClass()
{
obj = new DisposableObject();
list = new List<string>();
c = 114;
}
public void Dispose()
{
obj.Dispose();
}
}
public class DisposableObject : IDisposable
{
public void Dispose()
{
// Free resource
Console.WriteLine("Dispose DisposableObject");
}
}
公共类MyDataClass:IDisposable
{
私人可处分物;
私人名单;
私人INTC;
公共MyDataClass()
{
obj=新的可处置对象();
列表=新列表();
c=114;
}
公共空间处置()
{
obj.Dispose();
}
}
公共类可处置对象:IDisposable
{
公共空间处置()
{
//免费资源
Console.WriteLine(“处置可处置对象”);
}
}
当我运行代码分析时,我得到CA1063警告,它显示我应该在MyDataClass实现中的Dispose()方法中调用GC.SuppressFinalize()方法
我真的对CA1063警告感到困惑。因为据我所知,我应该调用GC.SuppressFinalize()向垃圾收集器指示:
“嘿,GC,不要担心这个物体,因为我已经为你做了所有的清洁工作!”
所以请确认我是否错了。如果我将添加GC.SuppressFinalize()我将去掉CA1063,但这将导致GC不会清理我的对象。因此,我将有一个内存泄漏,因为其他类成员(托管代码)将不会被清理
如果我将添加GC.SuppressFinalize()
,我将摆脱CA1063
但这将导致GC无法清理我的对象
不,您的对象仍将被收集
“嘿,GC,不要担心这个物体,因为我已经为你做了所有的清洁工作!”
您实际上只是说:不要担心这个对象的终结器(析构函数)。如果有
这就是代码分析出错的地方:您的类确实有一个
IDisposable.Dispose()
方法,但它没有析构函数。因此,警告毫无意义,保护过度,触发原因错误。禁用或忽略它 方法GC.SuppressFinalize()
指示VM不要运行终结器。这是C#中看起来很滑稽的方法:
~MyDataClass()
要删除警告,您需要密封您的类,或者实现完整的。我感觉您仍然感到困惑,尽管已经接受了答案。让我解释一下: 垃圾收集器(GC)的任务是从内存中删除任何无法访问的对象 可达性 对象
A
仅当存在从任何GC根到该对象的任何引用链时才可访问。根的示例包括堆栈和任何静态字段。因此,要确定A
是否可访问,GC所要做的就是在堆栈上找到一个引用对象的引用,该引用对象有一个引用对象的引用。。。指的是对象A
。如果找不到这样的链,则无法访问对象a
。1
因此,一旦GC确定A
不可访问,它就会希望将其从内存中删除。
但是,在此之前,GC检查A
是否有必须运行的终结器(~A
)。如果没有,它将从内存中删除A
,并完成GC
定稿
但是,如果A
具有必须运行的终结器,则在终结器完成之前,它无法从内存中删除对象。因此,它向终结器队列中添加了对a
的引用,并且还没有从内存中删除对象。现在,垃圾回收器已使用A
完成。但是,当GC再次运行时,它将再次尝试确定A
是否可访问。幸运的是,终结器队列也是垃圾收集器的根之一,因此它确定存在从终结器队列到a
的引用,因此a
是可访问的,并且不会再次从内存中删除
随之而来的是终结器线程,该线程定期检查终结器队列中是否有任何对象。如果有,它将选择一个并运行其终结器方法。最终,终结器线程将运行A
的终结器。完成此操作后,将从终结器队列中删除对A
的引用
清理
然后,一段时间后,垃圾收集器再次运行,并尝试再次确定A
是否可访问。由于它现在不在任何地方引用,甚至不从终结器队列引用,A
无法访问。GC从内存中删除A
您可以看到,通常GC可以在检测到无法访问的对象的同一个收集周期中删除这些对象,但是当一个对象有一个需要运行的终结器时,收集该对象可能需要多个周期。因此,CA1063建议您将
GC.SuppressFinalize()
放在Dispose
方法中,让GC知道在将对象从内存中删除之前不需要完成对象。因此,对象最终总是从内存中删除
请注意,如果没有终结器,则不必添加GC.SuppressFinalize()
,因此在这方面,CA1063警告有点多余
可以找到关于垃圾收集器的更深入的信息
1)可达性是在处理引用后将引用设置为
null
的常见原因。这使得引用的对象很可能无法访问,因此将删除候选对象
2)通过使用终结器从另一个可访问对象或根(例如静态字段)添加对A
的引用,可以(但不建议)恢复A
。这会使A
再次可访问,垃圾收集器不会将其删除。然而,它的终结器w