垃圾收集器C#,关于'清除'对象的问题

时间:2011-06-15 15:05:29

标签: c# garbage-collection

我读了一些关于垃圾收集的信息(它是如何工作的等等)。我试着理解它是如何运作我的例子,但我认为我有问题。我知道垃圾收集器在以下情况下运行:
记忆力不够,
你调用GC.Collect()。
这是我的代码:

public partial class Form1 : Form
{
    public Testing _d;
    public Boolean _first = false;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (!_first)
        {
            _d = new Testing();
            int test = _d.DoSomething("example");
        }
    }

    private void button2_Click(object sender, EventArgs e)
    {
        _first = true;
    }

    private void button3_Click(object sender, EventArgs e)
    {
        //if (_first)
        //{
        //    _d = null;
        //}
        GC.Collect();
    }
}

public class Testing
{
    private ASCIIEncoding _ascii;
    private bool _disposed = false;

    public Testing()
    {
        _ascii = new ASCIIEncoding();
    }

    public int DoSomething(string message)
    {
        return _ascii.GetByteCount(message);
    }
}

当我点击button1时,我正在创建新的对象测试。 _d是对这个新对象的引用。我正在使用JetBrains dotTrace Memory转储内存并看到这个新对象存在。单击button2后,我将boolean _first设置为true,以便_d变得无法访问。此时我想当我运行GC.Collect()GC将从堆栈中“清除”此对象,但我发现它仍然存在。我误解了GC的工作?或者我这样做错了? 当我设置_d = null;

时,它正在工作

5 个答案:

答案 0 :(得分:8)

单击Button2不会使_d无法访问。

GC仅收集未被根对象引用的对象 只要您的表单引用_d,就不会收集它。

答案 1 :(得分:4)

这是因为_d是对您设置且永不清除的Testing实例的引用。 _d仍然指向堆上的对象并保持此引用,直到您清除它为止(通过调用(_d = null)。

无法访问并不意味着无法将_d分配给其他内容,而是无法再次调用堆中的对象(因为代码中不存在引用)

因此GC无法清除它,因为它可能会在您的代码中稍后使用。

答案 2 :(得分:3)

设置first=false不会使GC _d实例无法访问。从逻辑上讲,您可能永远不会再次使用它,但它仍在Form1类中引用。

如果有人再次设置first=true,您是否不期望该对象仍可使用?

答案 3 :(得分:3)

您误解了GC如何确定可以访问的对象:当前本地范围中的变量引用的任何对象,任何静态变量以及可访问的对象的任何实例变量本身都是“可到达的” - 请查看将它作为图表,将前面提到的变量作为图的“根”。

在您的示例中,_d仍然保留对您的对象的引用,因此它仍然可以访问,并且不会被垃圾回收。

答案 4 :(得分:0)

如果你要调用GC.Collect(),所有对象,无论它们在内存中的时间长短,都会被考虑收集;但是,GC不会收集托管代码中引用的对象。查看this