CaliEventHandlerDelegateProxy утечка - PullRequest
3 голосов
/ 30 января 2020

У нас есть проблема на нашем веб-сайте, по-видимому, случайным образом (каждый день или около того, каждые 7-10 дней) веб-сайт перестает отвечать.

У нас есть два веб-сервера на Azure и мы используем Redis.

Мне удалось запустить DotNetMemory и перехватить его, когда он падает, и то, что я наблюдаю, составляет Event handlers leak два элемента увеличиваются в тысячи до того, как веб-сайт перестает работать , Эти два пункта CaliEventHandlerDelegateProxy и ArglessEventHandlerProxy. Как только сайт падает, мы получаем множество исключений Redis, которые не могут подключиться к серверу Redis. Согласно порталу Azure, нагрузка на наш сервер Redis в пиковые периоды никогда не превышает 10%, и мы следуем всем рекомендациям.

Я потратил много времени на просмотр нашего веб-сайта, чтобы убедиться, что нет очевидные утечки памяти, и залатали несколько случаев, которые пошли под радар. К счастью, это немного улучшило стабильность сайта. Вещи, которые мы проверили:

  • Все объекты iDisposable теперь обернуты с использованием блоков (мы делали это строго ранее, но мы обнаружили, что некоторые не были правильно расположены)
  • Обработчики событий отписались - в нашей кодовой базе очень мало
  • Мы довольно интенсивно используем WebUserControls. Каждой из них была передана текущая главная страница в качестве параметра. Мы удалили эту зависимость, так как думали, что может заставить G C не собирать страницу, возможно

Наша последняя проблема заключается в том, что когда веб-сервер работает нормально , но затем мы запускаем DotNetMemory и присоединяем его к процессу w3wp.exe, что приводит к быстрому увеличению утечек событий CaliEventHandlerDelegateProxy и ArglessEventHandlerProxy до сбоя сайта! Таким образом, cra sh воспроизводится только при запуске DotNetMemory. Вот скриншот того, что мы видели:

enter image description here

Сейчас я в растерянности, полагаю, что я исчерпал все возможности утечек памяти в наша база кода, и наше «решение» состоит в том, чтобы пулы приложений каждые несколько часов перезагружались, чтобы быть в безопасности.

Мы даже пытались обновить Redis до уровня Premium и даже обновили все диски на веб-серверы для твердотельных накопителей, чтобы посмотреть, помогает ли это вещам, которым оно не кажется.

Может кто-нибудь пролить свет на то, что может быть причиной этих проблем?

1 Ответ

4 голосов
/ 05 февраля 2020

Все объекты iDisposable теперь обернуты с использованием блоков (мы делали это строго ранее, но мы нашли несколько неправильно расположенных)

Мы не можем много сказать о cra sh без какой-либо информации об этом, но у меня есть некоторые предположения об этом. Я вижу 10 000 (!) Не расположенных объектов, обработанных в очереди завершения. Давайте начнем с них, найдите их все и добавьте вызов Dispose в свое приложение. Также я бы порекомендовал проверить, сколько системных дескрипторов используется вашим приложением. Существует ограничение операционной системы на количество дескрипторов, и если они превышены, больше нельзя создавать файловые дескрипторы, сетевые сокеты и т. Д. c. Я рекомендую это особенно, поскольку количество неразмещенных объектов.

Также, если у вас есть тайм-аут на доступ к Redis, получите профилировщик производительности и посмотрите, почему так. Я рекомендую получить JetBrains dotTrace и использовать режим TIMELINE , чтобы получить профиль вашего приложения, он покажет спящий поток, конфликт потоков и многое другое, что поможет вам найти проблему root. Вы можете использовать инструмент командной строки для получения данных профиля, чтобы не устанавливать приложение GUI на стороне сервера.

оно вызывает быстрое увеличение утечек событий CaliEventHandlerDelegateProxy и ArglessEventHandlerProxy

dotMemory не меняет код вашего приложения и не выделяет никаких управляемых объектов в профилированном процессе. Microsoft Profiling API внедряет dll (написанный на c ++) в процесс профилирования, это часть dotMemory, называемая Profilng Core, играющая роль «сервера» (где автономный dotMemory, написанный в C#, является клиентом). Профилирование Ядро выполняет некоторую работу со собранными данными перед отправкой их на клиентскую сторону, для этого требуется некоторая память, которая, конечно, выделяется в адресном пространстве процесса профилирования, но это не влияет на управляемую память.

Профилирование памяти может повлиять на производительность вашего приложения. Например, API профилирования отключает одновременный G C, когда приложение находится в режиме профилирования или сбор данных выделения памяти может значительно замедлить работу вашего приложения. Почему вы считаете, что CaliEventHandlerDelegateProxy и ArglessEventHandlerProxy размещаются только при профилировании dotMemory? Не могли бы вы описать, как вы это исследовали?

Обработчики событий не подписаны - в нашей кодовой базе очень мало

dotMemory сообщает об обработчике событий как об утечке. есть только одна ссылка на него - из источника события у него нет возможности отписаться от этого события. Проверьте все эти утечки, найдите свой код в коде, как это произошло. В любом случае, эти объекты хранят только 110,3 КБ. Почему вы решили, что ваш сайт из-за них потерпел крах?

Сейчас я в растерянности, полагаю, что я исчерпал все возможности памяти утечки в нашей кодовой базе

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

Надеюсь, если вы выполните все действия, которые я рекомендую вам выполнить (профилирование производительности, полное сравнение снимков и сравнение снимков, а не только просмотр проверок, проверка наличия огромного количества неразмещенных объектов), вы найдете и исправите проблему root.

...