Одноразовое состояние System.Threading.Timer не завершено до выхода из программы

Возможно, я делаю что-то глупое, в таком случае прошу прощения. Я работаю с классом System.Threading.Timer и устанавливаю таймеры включения-выключения, используя объект state для передачи управляющей информации. Все работает, как я и ожидал, за исключением того, что объект состояния не завершается до выхода из программы. Этот пример показывает, что я имею в виду.

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

Выход из этого:

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

Поскольку я устанавливаю время Timeout.Infinite для получения одноразового таймера, не должен ли пул потоков освобождать свои ссылки на объект состояния после отправки таймера, а не ждать до конца программы, как показано . Я обеспокоен тем, что это будет тонкой утечкой памяти.

Пожалуйста, просветите меня. :-)


person JamieH    schedule 05.10.2009    source источник
comment
Дох! Спасибо, ростеронацид. Я не буду делать это снова.   -  person JamieH    schedule 06.10.2009


Ответы (1)


В C# 'finalize' или деконструктор вызывается только тогда, когда объект удаляется сборщиком мусора и уничтожается. До тех пор эта функция не будет вызываться.

В вашем примере GC никогда не нужно будет запускать, поскольку это такие небольшие накладные расходы памяти.

Думаю, я был недостаточно конкретен, поэтому вместо того, чтобы обобщать происходящее, я укажу вам на статью MSDN, объясняющую поведение:

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

Finalize вызывается, когда объект становится «недоступным» (из-за сборки мусора, хотя нет гарантии, когда он будет запущен) или когда домен приложения закрывается.

person Erich    schedule 05.10.2009
comment
GC.Collect должен вызывать сборщик мусора, но финализаторы не запускаются сразу во время сборщика мусора. К сожалению, я не могу вспомнить подробности работы финализации в CLR. - person Michael; 06.10.2009