什么时候.net object = null垃圾收集游戏?范围重要吗?

SFu*_*n28 4 .net garbage-collection .net-4.0

伙计们,

如果我在一个长时间运行的方法中设置一个大对象.net为null(不一定是CPU密集型...只是长时间运行)它是垃圾收集的立即游戏还是该方法需要在对象之前完成准备垃圾收集?

Jon*_*eet 7

该方法不需要完成,但如果GC可以告诉您不再读取它,则也不需要将变量设置为null.例如:

public void Foo()
{
    SomeObject x = new SomeObject();
    // Code which uses x

    Console.WriteLine("Eligible for collection");

    // Code which doesn't use x.
}
Run Code Online (Sandbox Code Playgroud)

该对象有资格在指定点收集 - 当然,假设没有其他内容可以引用它.重要的是,是否有任何东西能够再次读取该值.您甚至可以为变量分配不同的值然后读取它,只要GC知道它不会再次看到原始值,那么它将不会充当GC根.例如:

using System;

class Bomb
{
    readonly string name;

    public Bomb(string name)
    {
        this.name = name;
    }

    ~Bomb()
    {
        Console.WriteLine(name + " - going boom!");
    }    

    public override string ToString()
    {
        return name;
    }
}

class Test
{
    static void Main()
    {
        Bomb b = new Bomb("First bomb");
        Console.WriteLine("Using bomb...");
        Console.WriteLine(b);
        Console.WriteLine("Not using it any more");

        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("Creating second bomb...");
        b = new Bomb("Second bomb");
        Console.WriteLine("Using second bomb...");
        Console.WriteLine(b);
        Console.WriteLine("End of main");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Using bomb...
First bomb
Not using it any more
First bomb - going boom!
Creating second bomb...
Using second bomb...
Second bomb
End of main
Second bomb - going boom!
Run Code Online (Sandbox Code Playgroud)

事实上,它可以变得更加极端:一个对象可以有资格进行垃圾收集,即使一个方法正在"运行"它,只要GC可以检测到没有任何东西可以再次读取一个字段.这是一个简短而完整的例子:

using System;

class Bomb
{
    int x = 10;

    ~Bomb()
    {
        Console.WriteLine("Boom!");
    }

    public void GoBang()
    {
        Console.WriteLine("Start of GoBang");
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("x={0}", x);
        Console.WriteLine("No more reads of x");
        GC.Collect();
        GC.WaitForPendingFinalizers();

        Console.WriteLine("Returning");
    }
}

class Test
{
    static void Main()
    {
        Bomb b = new Bomb();
        b.GoBang();
        Console.WriteLine("Still in Main");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Start of GoBang
x=10
No more reads of x
Boom!
Returning
Still in Main
Run Code Online (Sandbox Code Playgroud)

(不在调试器中运行它- 调试器延迟垃圾收集,以便您仍然可以观察变量.)

需要注意的一点是:您的问题涉及将对象设置为null ...该概念不存在.您只需将变量设置为null.值得区分的是两者.


Joe*_*oey 7

请参阅Raymond Chen的文章什么时候对象可用于垃圾回收?.基本上,它几乎可以在任何时候都有资格收集,甚至包括在你设置引用之前null.

但是,范围并不重要,因为这只是确定给定名称可见位置的编译器.它与对象的生命周期无关.