Использование памяти сайта ASP.NET довольно высокое

У меня есть сайт ASP.NET, который использует около 2 ГБ физической памяти в течение 3-4 дней, что для меня звучит очень плохо. На данный момент я настроил IIS для перезапуска процесса пула приложений, когда он достигает 500 МБ. Я хотел бы попытаться отследить проблему.

При создании нового экземпляра объекта в .NET у меня сложилось впечатление, что его не нужно освобождать, поскольку сборщик мусора .NET сделает это за меня.

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

18
задан webnoob 29 July 2013 в 08:14
поделиться

7 ответов

.NET будет управлять сборкой мусора для вас очень эффективно. Хотя для типов, реализующих IDisposable, разумно вызывать метод Dispose, это, вероятно, не ваша проблема. Утечки памяти могут происходить в .NET по многим причинам. Вот несколько:

  • Вы кэшируете слишком много данных для каждого пользователя в сессии.
  • Вы кэшируете слишком много данных на уровне приложения в кэше приложения или в статической переменной, такой как словарь.
  • Вы храните веб-контроли (или пользовательские элементы управления) на уровне сессии или приложения.
  • Вы подключаете экземпляры к событиям статических типов или к типам, на которые постоянно ссылаются (потому что они хранятся в кэше).

Надеюсь, это даст вам несколько идей о том, где искать.

UPDATE: Вам стоит посмотреть это видео об отладке ASP.NET.

UPDATE 2: По поводу вашего комментария к моему ответу скажу следующее. CLR будет собирать всю управляемую память, поэтому все объекты, которые вы создаете с помощью new, будут собраны. В этом смысле не имеет значения, реализует ли объект IDisposable или нет. Однако часто бывает так, что вам необходимо прямо или косвенно использовать собственные ресурсы (например, дескрипторы файлов, графические дескрипторы, соединения с базами данных, использование собственной - то есть неуправляемой - памяти). CLR не знает, как освободить эти ресурсы. Для этого в .NET существует понятие финализаторов. Финализатор - это виртуальный метод, который может реализовать разработчик класса. Когда вы это сделаете, CLR будет вызывать этот метод после того, как экземпляр данного типа будет лишен ссылок, и до того, как он будет собран. Финализаторы обычно содержат логику, которая освобождает эти ресурсы. Другими словами, когда тип нуждается в собственных ресурсах, он обычно имеет метод финализатора, который позволяет типу освободить эти ресурсы.

Что касается CLR, то на этом история заканчивается. CLR не имеет специфической обработки объектов, реализующих интерфейс IDisposable. Однако сборщик мусора .NET является недетерминированным по своей природе. Это означает, что вы не знаете, когда он будет запущен и будет ли он запущен. Это означает, что может пройти очень много времени, прежде чем ваши родные ресурсы будут очищены (потому что финализатор будет вызван только после сборки). Однако для многих ресурсов необходимо освободить их, как только вы закончите с ними работать. Например, соединения базы данных быстро заканчиваются, если их не закрывать, или при работе с GDI+ в .NET через пространство имен System.Drawing).

По этой причине был введен интерфейс IDisposable. Опять же, CLR и сборщик мусора не смотрят на этот интерфейс. Это контракт между типом и его пользователями, позволяющий пользователям напрямую освобождать базовые ресурсы объекта. При нормальном проектировании и финализатор объекта, и метод Dispose объекта будут вызывать один и тот же частный или защищенный метод, который освободит эти ресурсы. Когда тип реализует IDisposable, разумно вызвать его метод Dispose, когда вы закончите с ним, или обернуть объект в оператор using, чтобы освобождение собственных ресурсов было детерминированным.

Итак, вернемся к вашему вопросу. Все управляемые объекты будут собираться GC, но собственные ресурсы - нет. Поэтому типы могут реализовать метод finalizer, и эти объекты также обычно реализуют интерфейс IDisposable. Вызов Dispose на них явно и непосредственно освободит эти собственные ресурсы.

Надеюсь, это имеет смысл.

17
ответ дан 30 November 2019 в 08:10
поделиться

Может быть много причин для вашего большого использования памяти, но сборка мусора в .NET - очень точная вещь. То есть это много для вас, но иногда не так, как вы ожидали.

В частности, он может очищать только те объекты, на которые нет активных ссылок, поэтому, если вы закончили работу с классом, но что-то еще имеет ссылку на него, вы захотите удалить эту ссылку, чтобы GC мог восстановите эту память для вас. Кроме того, если у вас есть неактивные открытые соединения (например, с БД или чем-то еще), не забудьте закрыть и удалить их. Обычно мы заключаем такие объекты в , используя блоки , например:

using(SqlConnection conn = new SqlConnection(myConnString))
{ ...rest of code here }

Это автоматически закрывает и удаляет соединение. Это реализовано как блок try ... finally, поэтому соединение будет закрыто, даже если в блоке using возникнет исключение.

Кроме этого, ответ будет «профиль, профиль, профиль», пока вы не найдете свою утечку / узкое место / что угодно.

6
ответ дан 30 November 2019 в 08:10
поделиться

Есть несколько вещей, на которые вам следует обратить внимание:

Прежде всего, используете ли вы сессии? Они в proc или SQL сессиях? Если они в процессе, то какой таймаут установлен? Если у вас очень долгий таймаут, это может объяснить, почему вы используете так много памяти (пользовательские сессии будут храниться долгое время).

Во-вторых, утилизация объектов. Сборщик мусора .NET избавится от ссылок за вас, но когда вы создаете объекты, реализующие интерфейс IDisposable , вы всегда должны использовать ключевое слово using.

using(Foo foo = new Foo())
{
    ...
}

это эквивалентно тому, чтобы сделать :

Foo foo;
try
{
    foo = new Foo();
    ...
}
finally
{
    foo.Dispose();
}

и это гарантирует, что вы эффективно утилизируете свои объекты.

Если вы все еще не можете найти ничего очевидного в своем коде, вы можете профилировать его, начиная с методов, которые вызываются чаще всего. Информацию о хороших профилировщиках можно найти здесь. Это определенно приведет вас к источнику проблемы.

3
ответ дан 30 November 2019 в 08:10
поделиться

Утечки памяти в .NET все еще возможны. Это правда, что по большей части вам не нужно освобождать объекты (есть несколько исключений, таких как объект Graphics), но если вы сохраните ссылки на них, они не будут собираться сборщиком мусора, потому что на них по-прежнему ссылаются.

Если сборщик мусора видит, что на объект ссылаются где-то в любом месте вашего приложения, он не удалит его.

Прочтите статью Code Project об утечках памяти .NET и о том, как их найти и исправить.

1
ответ дан 30 November 2019 в 08:10
поделиться

Если ваше приложение ASP.NET использует события (а какое из них не использует), , то вы должны убедиться, что отписались от события .

Практическое правило:

Если вы используете + = для подписки на событие, тогда вам необходимо использовать - = в Dispose () метод отказа от подписки.

Есть много из ресурсов по этой теме , и у меня были проблемы с приложениями, в которых я работал, потому что вы -mill программист не понимает, что события могут вызвать утечку памяти.

1
ответ дан 30 November 2019 в 08:10
поделиться

Используйте профилировщик памяти (либо в дампе памяти, либо в вашей реальной среде), когда ваша память превышает эти 500 МБ, чтобы понять, какие объекты занимают все это пространство.

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

1
ответ дан 30 November 2019 в 08:10
поделиться

Хотя это правда, что вам не нужно явно освобождать память, и сборщик мусора сделает это за вас, возможно, что код непреднамеренно удерживает ссылку на объект, чтобы предотвратить его собрано - это по сути утечка памяти.

В ASP.NET объекты остаются «живыми», пока на них ссылается кеш приложения и сеанса. Не зная ничего о вашем приложении, я бы посоветовал вам получить профилировщик памяти и более внимательно посмотреть, что именно находится в памяти, и удерживает ли кеш приложения или сеанса то, чего не следует.

0
ответ дан 30 November 2019 в 08:10
поделиться
Другие вопросы по тегам:

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