views:

135

answers:

1

I may be doing something dumb, in which case I apologize. I'm working with the System.Threading.Timer class, and am setting on-off timers, using a state object to pass control information. Everything is work as I expected, except that the state object doesn't get finalized until the program exits. This example shows what I mean.

class State
    : IDisposable
{
    public State()
    {
        Console.Out.WriteLine("State.State()");
    }
    ~State()
    {
        Console.Out.WriteLine("State.~State()");
    }

    void IDisposable.Dispose()
    {
        Console.Out.WriteLine("State.Dispose()");
    }
}


class Program
{
    public static void Callback(object obj)
    {
        Console.Out.WriteLine("entering Callback()");

        State state = (State)obj;

        // . . . // do stuff

        Console.Out.WriteLine("leaving Callback()");
    }


    public static void Main(string[] args)
    {
        Timer t = new Timer(Callback, new State(), 1000, Timeout.Infinite);

        Thread.Sleep(5000);

        t.Dispose();
        t = null;
        GC.Collect(10, GCCollectionMode.Forced); // prod GC to release "State"
        Console.Out.WriteLine("leaving Main()");
    }
}

The output from this is:

State.State()
entering Callback()
leaving Callback()
leaving Main()
State.~State()

Since I'm setting the Timeout.Infinite time to get a one-shot timer, shouldn't the thread pool release its reference(s) to the state object once the timer is dispatched, rather than waiting until the end of the program, as shown. I'm concerned that this will be a subtle memory leak.

Please enlighten me. :-)

A: 

In C#, the 'finalize' or deconstructor is only called when the object is garbage collected and destroyed. Until then, that function won't be called.

In your example, GC would never need to run, since it is such a small memory overhead.

I guess I wasn't specific enough, so instead of generalizing what is happening, I'll point you to the MSDN article explaining the behavior:

http://msdn.microsoft.com/en-us/library/system.object.finalize%28VS.71%29.aspx

Finalize is called when an object becomes "inaccessible" (via garbage collection, though there is no guarantee when it'll run), or when the application domain is shut down.

Erich
GC.Collect should force a GC, but finalizers aren't run immediately during a GC. Unfortunately, I can't remember the details of how finalization works in the CLR.
Michael