Сделал дамп памяти своего сетевого асинхронного приложения и прошелся по нему такой замечательной утилитой, как DebugDiag 2 Analysis от Microsoft. Она выдала ошибку и предупреждение, вот их содержание:
Error:
In NetworkApplication.DMP GC is running in this process. The Thread
that triggered the GC is 330.
Warning:
This thread is waiting for .net garbage collection to finish. Thread
330 triggered the garbage collection. The gargage collector thread
wont start doing its work till the time the threads which have
pre-emptive GC disabled have finished executing. The following
threads have pre-emptive GC disabled 330.
89,45% of threads blocked (534 threads).
Рекомендации по исправлению, которые дала тулза:
Error:
When a GC is running the .NET objects are not in a valid state and the
reported analysis may be inaccurate. Also, the thread that triggered
the Garbage collection may or may not be a problematic thread. Too
many garbage collections in a process are bad for the performance of
the application. Too many GC's in a process may indicate a memory
pressure or symptoms of fragmenation. Review the blog ASP.NET Case
Study: High CPU in GC - Large objects and high allocation rates
for more details.
Warning:
Review the callstacks for the threads that have preemptive GC Disabled
to see what they are doing which is preventing the GC to run. Review
the blog .NET Hang Case Study: The GC-Loader Lock Deadlock (a
story of mixed mode dlls) that gives some information on how to debug
these issue more.
Соответственно приложение асинхронное и работает на потоках ThreadPool с дефолтными настройками. Версия .NET: 4.6.2 x64, перевел для более оптимальной работы RyuJIT, который в первых версиях работал не очень хорошо. Может быть это даже и плюс, потому что в этой версии фреймворка доступны новые методы управления сборщиком мусора. ОC: Windows Server 2012 r2 x64
Вопрос: Вообще с GC возможно как то бороться в данном случае (когда он начинает "втыкать" не по детски)? Что нужно оптимизировать? Какие советы можете дать или как лично боролись с подобными проблемами (тоже интересно почерпнуть чужой опыт).
p.s. приводить какой либо пример кода нерационально, приложение большое, много кода.
Ответ
ИМХО, бороться с GC не надо. Надо стараться избегать лишнего, неоправданного memory traffic'а. Тема нетривиальная, но можно выделить два основных совета:
Избегать ненужного "старения" объектов (переходов из Gen0 -> Gen1 ->
Gen2);
Избегать частого создания/пересоздания объектов, попадающих в LOH (Large object heap, туда попадают объекты размером более 85000
байт).
P.S.: Попробуйте проанализировать дамп вашего процесса при помощи утилиты WinDBG при помощи команды !DumpHeap -stat (подробнее можно почитать на MSDN). Посмотрите объектов какого типа подозрительно много, проанализируйте историю создания этих объектов (команда GCRoot).
Комментариев нет:
Отправить комментарий