Утечка памяти, если не остановить таймер явно [дублировать]

61
задан Stephen Cleary 1 July 2011 в 16:33
поделиться

4 ответа

Вы можете ответить на этот и подобные вопросы с помощью windbg, sos и !gcroot

0:008> !gcroot -nostacks 0000000002354160
DOMAIN(00000000002FE6A0):HANDLE(Strong):241320:Root:00000000023541a8(System.Thre
ading._TimerCallback)->
00000000023540c8(System.Threading.TimerCallback)->
0000000002354050(System.Timers.Timer)->
0000000002354160(System.Threading.Timer)
0:008>

. В обоих случаях встроенный таймер должен предотвратить GC объекта обратного вызова (через GCHandle). Разница в том, что в случае System.Timers.Timer обратный вызов ссылается на объект System.Timers.Timer (который реализован внутренне с помощью System.Threading.Timer)

28
ответ дан John 26 August 2018 в 05:05
поделиться

В таймере 1 вы даете ему обратный вызов. В timer2 вы подключаете обработчик событий; это настраивает ссылку на ваш класс программы, что означает, что таймер не будет GCed. Поскольку вы никогда больше не используете значение timer1 (в основном так же, как если бы вы удалили var timer1 =), компилятор достаточно умен, чтобы оптимизировать эту переменную. Когда вы нажмете на вызов GC, ничего больше не ссылается на timer1, поэтому его «собрано».

Добавить консоль. Записи после вызова GC для вывода одного из свойств таймера 1, и вы заметите, что он больше не собирается .

0
ответ дан Andy 26 August 2018 в 05:05
поделиться

FYI, с .NET 4.6 (если не раньше), это больше не будет истинным.

Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Invoking GC.Collect...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...
Stayin alive (2)...
Stayin alive (1)...

Когда я смотрю на реализацию System.Threading.Timer , это означает, что ваша тестовая программа, когда она выполняется сегодня, не приводит к сбою мусора. что в текущей версии .NET используется связанный список активных объектов таймера, и этот связанный список удерживается переменной-членом внутри TimerQueue (которая представляет собой одноэлементный объект, поддерживаемый статическим переменная члена также в TimerQueue). В результате все экземпляры таймера будут оставаться в живых до тех пор, пока они активны.

0
ответ дан Erv Walter 26 August 2018 в 05:05
поделиться

Я недавно искал эту проблему, посмотрев некоторые примеры реализации Task.Delay и сделав некоторые эксперименты.

Оказывается, независимо от того, является ли System.Threading.Timer GCd, зависит от того, как вы постройте его !!!

Если построено только с обратным вызовом, то объект состояния будет сам таймер, и это предотвратит его GC'd. Это, кажется, нигде не документировано, но без него чрезвычайно сложно создать огонь и забыть таймеры.

Я нашел это из кода в http://www.dotnetframework.org/ default.aspx / DotNET / DotNET / 8 @ 0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Threading / Timer @ cs / 1 / Timer @ cs

Комментарии в этом коде также указывают, почему всегда лучше использовать callback-only ctor, если обратный вызов ссылается на объект таймера, возвращаемый новым, поскольку в противном случае может быть ошибка гонки.

6
ответ дан Nick H 26 August 2018 в 05:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: