По крайней мере два десятка клиентов моего работодателя сообщают, что наше приложение .NET 3.5 зависает / зависает / перестает отвечать, обычно на 10–90 секунд, а затем снова реагирует.
Я видел это в случаях высокой загрузки ЦП, когда .NET явно считал, что ЦП имеет более высокий приоритет, чем сборка мусора. Затем, в самый последний момент, он выполнил сборку мусора, заняв много времени.
Я был удивлен, узнав, что сборщик мусора .NET 3.5, похоже, приостанавливает работу приложения.
Существует три режима: «вытесняющий», «одновременный» и «фоновый» сборщик мусора. Предварительно можно приостановить заявку. AFAIR, были времена, когда потоки действительно были в режиме приостановки Похоже, это уже не так.
В чем может быть причина?
0:002:x86> !threadpool
CPU utilization 81%
К вашему сведению: 81% - это магическое значение , указывающее на выполняемую сборку мусора, а также предотвращающее создание новых потоков в пуле потоков.
Вы определили поток 37 как поток GC и приостановили работу приложения.
Одна из возможных причин - финализатор блокировки. Однако, похоже, что это не так. Поток финализатора все еще ожидает события финализатора:
0:002:x86> k
# ChildEBP RetAddr
00 062bfa1c 760c5943 ntdll_77100000!NtWaitForMultipleObjects+0xc
01 062bfbb0 760c57f8 KERNELBASE!WaitForMultipleObjectsEx+0x133
02 062bfbcc 7114a136 KERNELBASE!WaitForMultipleObjects+0x18
03 062bfbec 7114e102 mscorwks!WKS::WaitForFinalizerEvent+0x77
04 062bfc00 710b965f mscorwks!WKS::GCHeap::FinalizerThreadWorker+0x49
Однако кажется, что некоторые потоки не могут быть приостановлены (столбец PreEmptive GC):
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
37 8 2348 28150ee0 b020 Disabled 681660a4:681660a4 01ef2e28 1 MTA (GC)
40 7 2f6c 281539d8 180b222 Disabled 00000000:00000000 01ef2e28 0 MTA (Threadpool Worker)
Кажется, что этот рабочий поток связан с теми записями таймера, о которых вы уже упоминали:
0:040:x86> k
[...]
0b 0e51f5b0 710b965f mscorwks!AddTimerCallback_Worker+0x66
[...]
Посмотрим:
AsyncTimerCallbackCompletion TimerInfo@4102d170
--------------------------------------
Number of Timers: 73
--------------------------------------
Completion Port Thread:Total: 1 Free: 1 MaxFree: 8 CurrentLimit: 0 MaxLimit: 1000 MinLimit: 4
0:040:x86> dp 4102d170 L5
4102d170 715e33d8 4102d320 0835739e 711381c9
4102d180 07a67be8
0:040:x86> dp 07a67be8 L2
07a67be8 00000001 01ddd1b0
0:040:x86> !do poi(01ddd1b0)
Name: System.Threading._TimerCallback
[...]
Похоже, вы используете System.Threading.Timer
.
Я не уверен на 100%, правильно ли я делаю эту часть, но он предлагает вам остановить таймер при вызове обратного вызова:
0:040:x86> k
# ChildEBP RetAddr
00 0e51f34c 706c9f4c mscorwks!CompareExchangeMP+0x8
01 0e51f370 702866d7 mscorlib_ni+0x1e9f4c
[...]
0:040:x86> !ip2md 702866d7
MethodDesc: 6fd71474
Method Name: System.Timers.Timer.Stop()
Пожалуйста, убедитесь, что вы правильно используете таймер потоков