C#垃圾回收器,关于“清除”对象的问题

4

我阅读了一些与垃圾回收相关的信息(如其工作原理等)。我尝试通过自己的示例来理解它是如何工作的,但是我认为我遇到了问题。我知道垃圾收集器在以下情况下运行:
内存不足时,
您调用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时,我正在创建一个名为Testing的新对象。_d是对这个新对象的引用。我使用JetBrains dotTrace Memory转储内存并查看这个新对象是否存在。在点击button2后,我将布尔值_first设置为true,以使_d变得不可访问。此时,我认为当我运行GC.Collect()时,GC会从堆栈中“清除”这个对象,但我看到它仍然存在。我对GC的工作有误解吗?还是我的做法有误?
当我设置_d = null;时,它可以正常工作。

你在这里试图解决什么问题?你是否有实际的分析数据表明你的应用程序存在内存泄漏问题? - Cody Gray
5个回答

8

点击 Button2 按钮不会使 _d 变得无法访问。

垃圾回收器只会清理那些没有被根对象引用的对象。
只要您的表单有对 _d 的引用,它就不会被回收。


严谨/显而易见的提示:即使表单本身是不可达的,只要表单有对_d的引用,_d就可以被收集。 - Brian

4
这是因为_d是对您设置并从未清除的Testing实例的引用。 _d仍然指向堆上的对象,并将保持此引用直到您清除它(通过调用_d = null)。
不可达并不意味着_d不能分配给其他内容,而是堆中的对象没有被再次调用的机会(因为代码中不存在任何引用)。
因此,GC无法清除它,因为它可能在您的代码中稍后仍然被使用。

这意味着我不用担心它,还是应该将其设置为null? - damned
我通常不会担心这个问题;一旦表单本身无法访问,它仍然可以被收集。如果“Testing”非常大,并且在“button3_Click”之后表单可能会保留而没有重新分配“_d”,那么将“_d”置为空可能是一个好主意。 - Brian

4

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

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


3
你误解了GC如何确定对象的可达性:任何在当前局部作用域中被变量引用、任何可达对象的静态变量和实例变量本身都是“可达”的——可以将其视为以前述变量为图的“根”。在你的示例中,_d 仍然持有对你的对象的引用,因此它仍然是可达的,不会被垃圾回收。

1
如果您调用GC.Collect(),所有对象,无论它们在内存中存在多长时间,都将被考虑进行垃圾回收;但是,在托管代码中引用的对象不会被GC回收。请参见this

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接