Это утечка памяти или сборка мусора это исправит - PullRequest
4 голосов
/ 21 февраля 2012

Допустим, у меня есть кнопка, которую нажимают, и она делает это:

public void ButtonClick(object sender, EventArgs e)
{
  System.Timers.Timer NewTimer = new System.Timers.Timer();
  NewTimer.AutoReset = false;
  NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
  NewTimer.Interval = 1000;
  NewTimer.Start(); 
}

public void TimerElapsed(object sender, ElapsedEventArgs e)
{

}

Если эту кнопку нажимают 100 раз, что происходит с теми экземплярами, которые были созданы?Сработает ли сборщик мусора или нужно вызвать метод System.Timers.Timer.Close, и если это произойдет, откуда вы вызываете его?

Ответы [ 3 ]

5 голосов
/ 21 февраля 2012

Нет, это не приведет к утечке памяти.Фактически, способ написания вашего кода не гарантирует правильного выполнения.Timers.Timer на самом деле является просто оберткой над Threading.Timer, и он явно указан как подлежащий сбору, даже если он в данный момент работает.

http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx

Здесь вы не сохраняете ссылку на него, и, следовательно, следующий GC может собрать егопока ваша форма еще работает и до того, как событие сработает,

РЕДАКТИРОВАТЬ

Документация для Timers.Timer представляется неверной.Экземпляр Timer не будет собран, если на него нет ссылок.Это действительно будет жить на

var timer = new System.Timers.Timer
{
    Interval = 400,
    AutoReset = true
};
timer.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer.Enabled = true;

WeakReference weakTimer = new WeakReference(timer);
timer = null;

for (int i = 0; i < 100; i++)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
}

Console.WriteLine("Weak Reference: {0}", weakTimer.Target);
Console.ReadKey();
2 голосов
/ 22 февраля 2012

После ответов the_joric и JaredPar и запуска тестов профилировщика, которые показали, что таймеры зависали после того, как сборщик мусора запускался, по той причине, что они задерживались, потому что есть ссылка на обработчик событий, оставшийся вокруг. Для более подробного объяснения см. этот ответ.

Реальный ответ - утечка памяти, если таймер не закрыт в обработчике прошедшего события.

Просто хочу показать, что, хотя я доверяю ответам SO (может быть, слишком) от великих авторов, они могут быть немного не в порядке.

2 голосов
/ 21 февраля 2012

Они будут собраны после того, как метод оставлен. TimerElapsed будет вызываться или не вызываться в зависимости от того, когда Timer будет завершен. Скорее всего, он будет мертв задолго до того, как пройдет 1 секунда.

Когда вы вызываете Timer.Close(), вы, таким образом, вызываете Timer.Dispose(), который отменяет регистрацию таймера из очереди таймера, и в этом случае TimerElapsed не будет вызываться (конечно, если он не был вызван ранее).

Если вы оставите таймер не закрытым, GC даже вызовет Finalize(), что, в свою очередь, вызовет Dispose(). Но нет точных знаний, когда это произойдет:)

См. Пример ниже, Console.Out.WriteLine("called!!!") никогда не выполнится:

using (System.Timers.Timer NewTimer = new System.Timers.Timer())
{
    NewTimer.AutoReset = false;
    ElapsedEventHandler TimerElapsed = (sender, args) => { Console.Out.WriteLine("called!!!"); };
    NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
    NewTimer.Interval = 1000;
    NewTimer.Start();
}

Thread.Sleep(3000);
...