Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is .net object = null game for garbage collection? Does scope matter?

Folks,

If I set a large object to .net to null in the middle of a long-running method (not necessarily CPU intensive...just long-running) is it immediately game for garbage collection OR does the method need to complete before the object is ready for garbage collection?

like image 882
SFun28 Avatar asked Dec 08 '22 00:12

SFun28


1 Answers

The method doesn't need to complete, but neither do you need to set the variable to null, if the GC can tell you're not going to read from it again. For example:

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

    Console.WriteLine("Eligible for collection");

    // Code which doesn't use x.
}

The object is eligible for collection at the indicated point - assuming nothing else has kept a reference to it, of course. The important thing is whether anything is ever going to be able to read that value again. You can even assign the variable a different value and then read it, and so long as the GC knows that it won't see the original value again, that won't act as a GC root. For example:

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");
    }
}

Output:

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 fact, it can get more extreme than that: an object can be eligible for garbage collection even while a method is running "in" it so long as the GC can detect that nothing can ever read a field again. Here's a short but complete example:

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");
    }
}

Output:

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

(Run this not in the debugger - the debugger delays garbage collection so that you can still watch variables.)

One point to note: your question talks about setting an object to null... that concept doesn't exist. You only ever set a variable to null. It's worth distinguishing between the two.

like image 190
Jon Skeet Avatar answered Mar 15 '23 13:03

Jon Skeet