7
public class MyClass {
  private static MyClass heldInstance;

  public MyClass() {
    heldInstance = this;
  }
}

Assuming an instance of MyClass is not rooted in any other way, will the private static reference here prevent it from being garbage collected?

zastrowm
  • 8,017
  • 3
  • 43
  • 63
Jeff Stewart
  • 803
  • 1
  • 8
  • 14
  • 1
    possible duplicate of [Do static members ever get garbage collected?](http://stackoverflow.com/questions/6600093/do-static-members-ever-get-garbage-collected) EDIT: In short, no, I don't believe it will. For example, in the code you posted, there's no reason why the public constructor couldn't have had `if (heldInstance == null)` Other than that, _instances_ in which the only held references are from itself to itself will _eventually_ be collected by the GC once it determines that it's no longer accessible. – Chris Sinclair Feb 26 '13 at 21:37
  • Yes, they get collected just before the AppDomain is unloaded. That's inconsequential unless the class has a finalizer. – Hans Passant Feb 26 '13 at 21:45
  • 3
    The fact that a static field of the class is referencing an instance *of the same class* is irrelevant. Static fields are roots; they'll keep anything alive that you put into them regardless of its type. – Eric Lippert Feb 26 '13 at 22:11

2 Answers2

9

The class you posted will not be garbage collected. You can test this by giving it a finalizer with a console output:

public class MyClass
{
    private static MyClass heldInstance;
    public MyClass()
    {
        heldInstance = this;
    }
    ~MyClass()
    {
        Console.WriteLine("Finalizer called");
    }
}
class Program
{
    static void Main(string[] args)
    {
        var x = new MyClass(); // object created

        x = null; // object may be eliglible for garbage collection now

        // theoretically, a GC could happen here, but probably not, with this little memory used
        System.Threading.Thread.Sleep(5000);

        // so we force a GC. Now all eligible objects will definitely be collected
        GC.Collect(2,GCCollectionMode.Forced);

        //however their finalizers will execute in a separate thread, so we wait for them to finish
        GC.WaitForPendingFinalizers();

        System.Threading.Thread.Sleep(5000);
        Console.WriteLine("END");

    }
}

The output will be:

END
Finalizer called

Which means that the class only gets collected at the final teardown of the application, not during a regular garbage collection.

If you create multiple instances of this class like this:

var x = new MyClass();
x = new MyClass();
x = new MyClass();
x = new MyClass();

then all except the most recent one will be garbage collected.

You would get

Finalizer called
Finalizer called
Finalizer called
END
Finalizer called
HugoRune
  • 13,157
  • 7
  • 69
  • 144
  • 1
    Note that this is true only because `heldInstance` is static. There is nothing special about the fact that an instance of `MyClass` has a reference to itself. So, yes "a class that references itself" can be garbage collected. However, the class in the example cannot. – dgvid Feb 26 '13 at 22:01
2

The garbage collector determines which objects are reachable and will collect those that are not. To determine whether an object is reachable, the collector will start with the so called roots. Among the roots are the things currently on the evaluation stack, but also static fields. The collector will follow the references to objects from the roots to any object, and from such an object to any other object, and so on. Each object that has been visited this way is reachable and will therefore be kept alive.

In your case the static field is one of the garbage collector's roots, and therefore it will never collect any object that is referenced (indirectly) by that field. However, if you set the field to null then that field no longer references the instance and the instance may be collected.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157