18

Consider the following code :

class TestTimerGC : Form
{
    public TestTimerGC()
    {
        Button btnGC = new Button();
        btnGC.Text = "GC";
        btnGC.Click += (sender, e) => GC.Collect();
        this.Controls.Add(btnGC);

        System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
        tmr.Interval = 1000;
        tmr.Tick += (sender, e) => this.Text = DateTime.Now.ToString();
        tmr.Start();
    }
}

If I'm not mistaken, after the tmr variable goes out of scope, the Timer isn't referenced anywhere, so it should be eligible for garbage collection. But when I click the GC button, the timer continues to run, so I guess it wasn't collected...

Does anyone have an explanation for that ?

PS: it's not a real program of course, I was just trying to prove a point to someone... but my proof didn't work ;)

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758

1 Answers1

22

OK, I think I know what's going on... I looked at the code of the Timer class with Reflector, and I found the following instruction in the setter of the Enabled property :

this.timerRoot = GCHandle.Alloc(this);

So, when it is started, the timer allocates a GCHandle for itself, which prevents its collection by the GC...

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • 1
    MSDN also says that at https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.timer.enabled: "The timer is not subject to garbage collection when the value is true" – Roman Apr 02 '19 at 10:18