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

Garbage Collector C#, question about 'clearing' objects

我阅读了一些有关垃圾收集的信息(它的工作方式等)。 我尝试了解示例的工作方式,但我认为有问题。 我知道垃圾收集器在以下情况下运行:
内存不足,
您调用GC.Collect()。
这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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;时,它正在工作


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

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


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

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


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

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

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


您误解了GC如何确定可访问对象:当前局部范围内的变量引用的任何对象,可访问对象的任何静态变量和任何实例变量本身都是"可访问的"-将其视为具有上述变量作为图的"根"的图。

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


如果要调用GC.Collect(),则将考虑所有对象(无论它们在内存中已经存放了多长时间);但是,GC不会收集托管代码中引用的对象。检查一下