Вопрос или проблема
У нас есть IIS, работающий на двух серверах (IIS8 и 10), и в последнее время мы сталкиваемся с очень высоким потреблением памяти нашими приложениями ASP.NET WebForms, к которым чаще всего обращаются через страницы aspx.
Что происходит, так это то, что со временем наши пуллы приложений потребляют все больше и больше памяти, пока физическая память на сервере (64 ГБ) практически не заканчивается. Это определенно ненормально.
Мы пытались выяснить, почему это происходит, но у нас кончились идеи. Неясно, является ли это утечкой памяти в нашем приложении или нормальным поведением, поэтому, возможно, кто-то сможет прояснить этот вопрос.
Факты:
-
Со временем пуллы приложений резервируют И ИСПОЛЬЗУЮТ все больше и больше памяти, которая не освобождается (диспетчер задач говорит, что как рабочий набор, так и размер коммита очень высоки, так что это действительно используется/удерживается, верно?)
-
Профайлеры памяти, такие как ANTS, .dotMemory, .NET MemoryProfiler, сообщают, что потребление управляемой памяти довольно низкое, скажем, 20-200 МБ, и показывают много неконтролируемой памяти, которая используется, но свободна.
-
Они не дают нам никаких подсказок о том, что может вызывать использование неконтролируемой памяти, даже с помощью снимков и детализированных методов профилирования.
-
Если мы “нажимаем” на главной странице клавишу F5, не освобождая ее, мы можем увеличить потребление памяти до 2-5 гигабайт за одну минуту. Это немного сумасшествие.
-
Мы знаем, что IIS/пуллы приложений склонны резервировать память в оппортунистическом режиме, чем больше доступно памяти, но это слишком много.
-
Единственное, что мы видим, это то, что главная страница, похоже, удерживается в памяти со своими элементами управления и объектами ComponentModel, но нигде в профилировщиках памяти нет единой ссылки на какие-либо из наших объектов страниц или классов собственного пространства имен.
-
Потребление памяти, по словам некоторых, в прошлом году было нормальным и останавливалось на уровне 2-3 гигабайтов в общем, но теперь мы не можем воспроизвести это с помощью старой версии приложения.
-
Это происходит и на свежей локальной установке IIS под WIN10.
-
Приложение собрано в режиме релиза, оптимизировано, в данный момент скомпилировано в одну DLL, также пробовали без этого, флаг трассировки включен, размер 5 МБ.
Кажется, нам нужно разобрать приложение, разделить его на несколько модулей и посмотреть, как они ведут себя. Собранные во время выполнения сборки/библиотеки могут, но не должны быть проблемой. Мы на самом деле не ссылаемся на столько много (FreeTextBox, Microsoft ReportViewer, SharpCompress, Crystal Reports, AjaxControlToolKit 15), мы уже удалили все, кроме CrystalReports/AjaxControlToolKit, чтобы посмотреть, что произойдет, но ничего не изменилось.
Мы также используем много элементов управления WebForms, включая таймеры и UpdatePanels иногда.
Мы также не знаем, как найти виновника, используя профайлеры памяти, предполагая, что есть скрытая ссылка, которая вызывает удержание одной или нескольких страниц aspx в памяти, потому что экземпляры классов .NET никогда не показывают никаких ссылок на что-либо.
Мы были бы рады получить ЛЮБУЮ подсказку о том, что мы могли бы неправильно понять относительно резервирования памяти или того, как устранить эту проблему с потреблением памяти.
Большое спасибо за уделенное время!
ПОПРАВКА (забыл упомянуть):
– Мы добавили GC.Collect/WaitForPendingFinalizers/GC.Collect в нашу функцию Page_Load на стартовой странице, чтобы посмотреть, поможет ли это, и это действительно помогает на некоторое время или немного, пока не возникнет другая ситуация давления (с F5), когда потребление памяти снова резко возрастает.
Когда GC.WaitForPendingFinalizers помогает, это может быть признаком использования памяти потоками. Если вы запускаете новый отдельный поток в page_load, он может использовать много памяти. Начните диагностику проблемы, проверив количество потоков в диспетчере задач.
Ответ или решение
Высокое использование памяти пулов приложений IIS: Причины и решения
Недавний рост использования памяти в пулах приложений IIS (Internet Information Services), особенно для веб-приложений на ASP.NET WebForms, является серьезной проблемой, требующей внимательного анализа. Данная статья направлена на понимание причин данного поведения, выявление возможных утечек памяти и предоставление путей решения проблемы.
Факторы, способствующие высокой памяти
-
Неправильное управление памятью в приложении
То, что вы отмечаете, — увеличение использования памяти с течением времени, возможно, указывает на утечку памяти в коде. Убедитесь, что все неуправляемые ресурсы (например, изображения, дескрипторы файлов, соединения с базой данных) освобождаются корректно. -
Потоки и фоновая работа
Вы упоминаете, что добавлениеGC.Collect()
помогает снизить использование памяти. Это может свидетельствовать о том, что в приложении создаются дополнительные потоки, которые удерживают память. Проверьте количество потоков в диспетчере задач и убедитесь, что вы освобождаете память в фоновых задачах. -
Проблемы с контроллерами на страницах
Использование множества контроллеров WebForms, таких как Timers или UpdatePanels, может привести к накоплению состояний на стороне сервера. Если состояние управления не очищается корректно, это может вызвать избыточное использование памяти. -
Управление сборщиками мусора
IIS может резервировать (реальными объектами) больше памяти при наличии доступной физической памяти. Оптимизация процесса сборки мусора (Garbage Collection) и применяемая вами логика принудительной сборки мусора может еще больше усугубить проблему в пиковые моменты нагрузки.
Шаги по устранению проблемы
-
Использование инструментов мониторинга
Вы упомянули использование ANTS, .dotMemory и .NET MemoryProfiler, но может понадобиться глубокий анализ. Попробуйте использовать WinDbg с SOS (Son of Strike) для анализа утечек памяти более подробно. Это поможет выявить модули или библиотеки, которые удерживают память. -
Разделение приложения
Оптимизация кода и разделение вашего приложения на модули могут помочь в выявлении утечек памяти. Если проблема локализуется, это упростит диагностику и позволит выявить конкретные области, которые нужно улучшать. -
Регулярная проверка состояний контроллеров
Убедитесь, что все управляющие элементы, особенно те, что с состоянием (например, ASP.NET ViewState), очищаются при необходимости. Это может включать четкое управление жизненным циклом компонентов и их состояний. -
Проблемы с API и библиотеками
Часто сторонние библиотеки могут вызывать утечки памяти. Проверьте, нет ли известных проблем с вашими использованными библиотеками, такими как Crystal Reports или AjaxControlToolkit. Обновление или исправление их может помочь. -
Проверка и оптимизация кода
Ваша проверка оптимизации "выпущенного" приложения является позитивным шагом. Чтобы выявить проблему, рекомендуется проводить статический анализ кода, чтобы убедиться, что никакие обекты не удерживаются после завершения их использования. -
Настройки пула приложений IIS
Рассмотрите возможность применения автоматического завершения работы пула приложений (recycling). Настройки "Memory Limit" в конфигурации пула приложений могут помочь предотвратить чрезмерное использование памяти путем принудительного "освежения" пула.
Заключение
На основании предоставленных вами фактов, проблема с памятью в IIS скорее всего обусловлена неэффективным управлением ресурсами либо в коде самого приложения, либо в конфигурации пула приложений. Важно систематично подойти к диагностике, учитывая особенности веб-технологий и поведения управления памятью в среде .NET. Успешное решение этих вопросов приведет к улучшению производительности и стабильности ваших веб-приложений.
Моя команда остается готовой помочь вам в дальнейшем, если возникнут дополнительные вопросы или потребуется уточнение каких-либо аспектов.