Добрый день.
Ситуация следующая:
В приложении Windows Forms создаю таймер,запускаю и привязываю событие:
public Form1 () {
InitializeComponent();
Timer t = new Timer();
t.Tick += new EventHandler(t_Tick);
t.Interval = 1000;
t.Start();
t = new Timer();
t.Tick += new EventHandler(t_Tick1);
t.Interval = 1000;
t.Start();
}
void t_Tick (object sender, EventArgs e) {
txtResult.Text = DateTime.Now.ToString();
GC.Collect();
}
void t_Tick1 (object sender, EventArgs e) {
txtResult2.Text = DateTime.Now.ToString();
GC.Collect();
}
Далее этой же переменной присваиваю другой таймер,т.е. доступ к первому таймеру потерян.
При наступлении события запускаю сборщик мусора. По идее первый таймер должен быть уничтожен
,но он работает. Пробовал и в Release и в Debug. У Рихтера похожий пример,
все работает правильно.
Почему таймер не уничтожается,а если таких операций будет 1000?
Это разве не утечка ресурсов?
Я что то не понимаю.
Буду рад любому мнению.
Timer подлежит сбору мусора, когда на этот объект не существует ссылок. Тот факт, что Timer все еще активен, не предотвращает его от утилизации.
Когда в таймере больше нет необходимости, следует использовать метод Dispose для освобождения ресурсов, которые занимает таймер.
1. Нельзя терять ссылки на объект класса Timer до тех пор пока он тебе нужен.
2. Что-бы отсановить таймер используй Dispose()
3. RTFM
PS Если начинаешь использовать како-то новый класс из фреймворка, потрать минутку и загляни в MSDN. Там как правило описаны особенности использования...
Re[2]: Не работает GC?
От:
Аноним
Дата:
16.04.07 05:42
Оценка:
спасибо всем за ответы.
То BluntBlind.
МСДН конечно читал.
Может не совсем точно выразился. Я использую не System.Threading.Timer,а System.Windows.Forms.Timer.
И вопрос именно что таймер НЕ УНИЧТОЖАЕТЬСЯ GC!
C System.Threading.Timer нет проблем все работает как надо. А вот почему не уничтожаеться System.Windows.Forms. Timer,то ли потому что все работает в одном потоке,то ли еще что то??
"Нельзя терять ссылки на объект класса Timer до тех пор пока он тебе нужен".
Абсолютно согласен,но ведь все мы люди,и утечки в С++ происходили именно по невнимательности,В CLR вроде бы от этого защита,так почему не уничтожаеться таймер??
Здравствуйте, Аноним, Вы писали:
А>Может не совсем точно выразился. Я использую не System.Threading.Timer,а System.Windows.Forms.Timer.
Да, тут я мог бы догадаться.
А>И вопрос именно что таймер НЕ УНИЧТОЖАЕТЬСЯ GC!
GC.Collect вызывает сборку мусора и это не гарантирует уничтожение твоего объекта. Почитай, как работает GC. Там есть такое понятие как поколения. И старайся избегать вмешательств в работу GC.
А>"Нельзя терять ссылки на объект класса Timer до тех пор пока он тебе нужен". А>Абсолютно согласен,но ведь все мы люди,и утечки в С++ происходили именно по невнимательности,В CLR вроде бы от этого защита,так почему не уничтожаеться таймер??
Это не утечка. Память будет собрана. Только произойдет это в любой момент, а ты расчитываешь, что твой объект жив.
У этого таймера тоже есть Dispose, а так же Stop() и св-во Enable.
По поводу поколений и самостоятельной работы GC я не подумал.
Похоже он для Windows Form продлевает жизнь данного объекта,как в Debug так и в Release.
Спасибо BluntBlind.
Здравствуйте, BluntBlind, Вы писали:
BB>Здравствуйте, Аноним, Вы писали:
А>>Может не совсем точно выразился. Я использую не System.Threading.Timer,а System.Windows.Forms.Timer.
Возможно ссылка на таймер сохраняется в приватном списке components?
Здравствуйте, <Аноним>, Вы писали:
А>По поводу поколений и самостоятельной работы GC я не подумал. А>Похоже он для Windows Form продлевает жизнь данного объекта,как в Debug так и в Release.
поколения тут ни при чем.
Таймер должен както узнавать что в очереди сообщений появилось WM_TIMER? должен!
Как он это делает? подписывается на обработку сообщений.
А что представляет собой подписка? подписка представляет собой делегат, который включает ссылку на объект и на метод в объекте.
Таким образом ссылка на таймер остается в делегате которым таймер подписался на обработку сообщений окна.
Чтобы таймер отписался его нужно выключить.
Т.е. перед тем как менять значение переменной timer, нужно сделать следующее:
Здравствуйте, _Morpheus_, Вы писали:
_M_>Таким образом ссылка на таймер остается в делегате которым таймер подписался на обработку сообщений окна. _M_>Чтобы таймер отписался его нужно выключить.
Да наверно, собственно для этого и сделан Dispose()
Здравствуйте, _Morpheus_, Вы писали:
А>В приложении Windows Forms создаю таймер,запускаю и привязываю событие. А>Далее этой же переменной присваиваю другой таймер,т.е. доступ к первому таймеру потерян. А>При наступлении события запускаю сборщик мусора. По идее первый таймер должен быть уничтожен, но он работает. Пробовал и в Release и в Debug. У Рихтера похожий пример, все работает правильно. А>Почему таймер не уничтожается,а если таких операций будет 1000? Это разве не утечка ресурсов? Я что то не понимаю.
_M_>Т.е. перед тем как менять значение переменной timer, нужно сделать следующее: _M_>
_M_>timer.Enabled = false;
_M_>timer = new Timer();
_M_>
Пошарился Reflectorom
Если Enable = true;
То вызывается
if (value)
{
if (this.timerWindow == null)
{
this.timerWindow = new TimerNativeWindow(this);
}
this.timerRoot = GCHandle.Alloc(this);
this.timerWindow.StartTimer(this.interval);
}
В MSDN про GCHandle.Alloc(this) есть такие слова:
Return Value
A new GCHandle that protects the object from garbage collection. This GCHandle must be released with Free when it is no longer needed.