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

时间:2011-01-11 17:19:35

标签: .net .net-4.0 garbage-collection

民间,

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

3 个答案:

答案 0 :(得分: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.
}

该对象有资格在指定点收集 - 当然,假设没有其他内容可以引用它。重要的是,是否有任何东西能够再次读取该值。您甚至可以为变量分配不同的值然后读取它,只要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");
    }
}

输出:

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!

事实上,它可以变得更加极端:一个对象可以有资格进行垃圾收集,即使方法正在“in”它运行,只要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");
    }
}

输出:

Start of GoBang
x=10
No more reads of x
Boom!
Returning
Still in Main

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

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

答案 1 :(得分:7)

参见Raymond Chen的文章When does an object become available for garbage collection?。基本上,它几乎可以在任何时候都有资格收集,甚至包括在您将引用设置为null之前。

范围并不重要,as that's only a compiler thing to determine where a given name is visible. It doesn't have anything to do with the lifetime of objects.

答案 2 :(得分:1)

假设以前持有的值不再被任何东西引用,它立即有资格进行垃圾回收。