垃圾回收器C#,关于';清除';对象

本文关键字:清除 对象 关于 | 更新日期: 2023-09-27 17:59:25

我读到了一些关于垃圾回收的信息(它是如何工作的等等)。我在做例子时试图理解它是如何运作的,但我觉得我有问题。我知道垃圾回收器在以下情况下运行:
内存不足,
调用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);
    }
}

当我单击按钮1时,我正在创建新的对象Testing_d是对这个新对象的引用。我正在使用JetBrains dotTrace内存转储内存,然后看到这个新对象存在。单击按钮2后,我将boolean _first设置为true,以便_d变得不可访问。在这一点上,我认为当我运行GC.Collect()时,GC会从堆栈中"清除"这个对象,但我发现它仍然存在。我误解了GC的工作?还是我做错了
当我设置_d = null; 时,它正在工作

垃圾回收器C#,关于';清除';对象

单击按钮2不会使_d无法访问。

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

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

如果有人再次设置first=true,你会不希望该对象仍然可用吗?

这是因为_d是对Testing实例的引用,您设置了该实例,但从未清除。_d仍然指向堆上的对象,并将维护此引用,直到您清除它为止(通过调用(_d = null)。

不可访问并不意味着_d不能分配给其他对象,而是堆中的对象没有机会再次被调用(因为代码中不存在引用)

因此,GC不可能清除它,因为它稍后可能仍在代码中使用。

您误解了GC是如何确定对象可访问的:当前本地作用域中的变量引用的任何对象、可访问对象的任何静态变量和任何实例变量本身都是"可访问的"-将其视为一个图,前面提到的变量作为图的"根"。

在您的示例中,_d仍然持有对对象的引用,因此它仍然是可访问的,不会被垃圾收集。

如果要调用GC.Collect(),则所有对象,无论它们在内存中存在多长时间,都将被视为集合;但是,GC不会收集托管代码中引用的对象。检查此