Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

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

Это автоматически закроет и удалит соединение; Я уверен, что это также дает вам попробовать/наконец бесплатно (кто-то дважды проверьте меня на этом, пожалуйста).

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

Ответ 3

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

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

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

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

является эквивалентом:

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

И это обеспечит эффективное удаление ваших объектов.

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

Ответ 4

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

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

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

Ответ 5

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

Общее правило:

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

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

Ответ 6

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

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

Ответ 7

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

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