Какие стратегии и инструменты полезны для обнаружения утечек памяти в .NET?

Я написал С++ в течение 10 лет. Я столкнулся с проблемами памяти, но они могли быть исправлены с достаточным усилием.

В последние пару лет я писал С#. Я считаю, что у меня все еще много проблем с памятью. Их трудно диагностировать и исправить из-за неопределенности, и потому, что философия С# заключается в том, что вам не придется беспокоиться о таких вещах, когда вы очень определенно делаете.

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

Какие стратегии и инструменты полезны для устранения утечек памяти в .NET?

Ответ 1

Я использую Scitech MemProfiler, когда я подозреваю утечку памяти.

До сих пор я нашел его очень надежным и мощным. Он спас мой бекон хотя бы один раз.

GC отлично работает в .NET IMO, но, как и любой другой язык или платформа, если вы пишете плохой код, происходят плохие вещи.

Ответ 2

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

    public void Dispose ()
    {
        // Dispose logic here ...

        // It a bad error if someone forgets to call Dispose,
        // so in Debug builds, we put a finalizer in to detect
        // the error. If Dispose is called, we suppress the
        // finalizer.
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

#if DEBUG
    ~TimedLock()
    {
        // If this finalizer runs, someone somewhere failed to
        // call Dispose, which means we've failed to leave
        // a monitor!
        System.Diagnostics.Debug.Fail("Undisposed lock");
    }
#endif

Ответ 3

Мы использовали Ants Profiler Pro от программного обеспечения Red Gate в нашем проекте. Он отлично работает для всех приложений на языке .NET.

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

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

class ParentObject
   Private mRelatedObject as New CRelatedObject
   public Readonly property RelatedObject() as CRelatedObject
      get
         mRelatedObject.getWithID(RelatedObjectID)
         return mRelatedObject
      end get
   end property
End class

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

class ParentObject
   Private mRelatedObject as CRelatedObject
   Public ReadOnly Property RelatedObject() as CRelatedObject
      Get
         If mRelatedObject is Nothing
            mRelatedObject = New CRelatedObject
         End If
         If mRelatedObject.isEmptyObject
            mRelatedObject.getWithID(RelatedObjectID)
         End If
         return mRelatedObject
      end get
   end Property
end class

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

Ответ 4

Вам все равно нужно беспокоиться о памяти, когда вы пишете управляемый код, если ваше приложение тривиально. Я предлагаю две вещи: во-первых, прочитайте CLR через С#, потому что это поможет вам понять управление памятью в .NET. Во-вторых, научитесь использовать такой инструмент, как CLRProfiler (Microsoft). Это может дать вам представление о том, что вызывает утечку памяти (например, вы можете взглянуть на фрагментацию кучи большого объекта)

Ответ 5

Вы используете неуправляемый код? Если вы не используете неуправляемый код, согласно Microsoft, утечки памяти в традиционном смысле невозможны.

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

От Как идентифицировать утечки памяти в среде общего языка на Microsoft.com

Утечка памяти может произойти в .NET. Рамочное приложение при использовании неуправляемый код как часть выражение. Этот неуправляемый код может памяти утечек и .NET Framework время выполнения не может решить эту проблему.

Кроме того, проект может кажется, есть утечка памяти. Эта условие может возникнуть, если многие большие объекты (такие как объекты DataTable) объявляются, а затем добавляются к (например, DataSet). ресурсы, которыми обладают эти объекты, могут никогда не будет выпущен, а ресурсы остаются живыми на протяжении всего программа. Это, по-видимому, утечка, но на самом деле это просто симптом того, как память выделяется в программе.

Для решения этой проблемы вы можете реализовать IDisposable. Если вы хотите увидеть некоторые стратегии управления памятью, я бы предложил искать IDisposable, XNA, управление памятью, поскольку разработчикам игр нужно иметь более предсказуемую сборку мусора, и поэтому она вынуждает GC выполнять свою работу.

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

Ответ 6

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

Ответ 7

У меня просто была утечка памяти в службе windows, которую я исправил.

Сначала я попробовал MemProfiler. Мне было очень сложно использовать и не совсем дружелюбно.

Затем я использовал JustTrace, который проще в использовании и дает вам более подробную информацию об объектах, которые не расположены правильно.

Это позволило мне легко решить проблему утечки памяти.

Ответ 8

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

Однако, ИМХО, было бы лучше рассмотреть индивидуальное решение - только вы действительно знаете, как долго вам нужно держать объекты вокруг, поэтому оптимальный подход к разработке вашего домашнего кода - это лучший подход.

Ответ 9

Лучше всего иметь в виду следить за ссылками на ваши объекты. Очень легко в конечном итоге навязать ссылки на объекты, которые вам больше не нужны. Если вы больше ничего не собираетесь использовать, избавитесь от него.

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

Ответ 10

Один из лучших инструментов - это Инструменты отладки для Windows и сбрасывание памяти используя adplus, затем используйте windbg и плагин sos, чтобы проанализировать память процесса, потоки и стеки вызовов.

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

Затем проанализируйте офлайн.

Ответ 11

Большие пушки - Инструменты отладки для Windows

Это потрясающая коллекция инструментов. Вы можете анализировать как управляемые, так и неуправляемые кучи, и вы можете делать это в автономном режиме. Это было очень удобно для отладки одного из наших приложений ASP.NET, которые сохраняли возможность утилизации из-за чрезмерного использования памяти. Я только должен был создать полный дамп памяти жизненного процесса, работающий на производственном сервере, все анализы были выполнены автономно в WinDbg. (Оказалось, что какой-то разработчик перегружал память сеанса в памяти.)

"Если это сломано..." в блоге есть очень полезные статьи по этой теме.

Ответ 12

После одного из моих исправлений для управляемого приложения у меня было то же самое, например, как проверить, что мое приложение не будет иметь такую ​​же утечку памяти после моего следующего изменения, поэтому я написал что-то вроде рамки проверки подлинности объекта, пожалуйста, посмотрите на пакет NuGet ObjectReleaseVerification. Вы можете найти здесь образец https://github.com/outcoldman/OutcoldSolutions-ObjectReleaseVerification-Sample и информацию об этом примере http://outcoldman.ru/en/blog/show/322

Ответ 13

В Visual Studio (Premium или Enterprise) вы можете открыть дамп кучи и отладить управляемую кучу. Когда вы нажимаете на тип, приведенные ниже вкладки позволят вам увидеть, какие другие типы ссылаются на эти объекты.

Вы можете использовать PerfView для более детального анализа:

  1. В меню "Память" выберите "Сделать снимок кучи".

  2. В появившемся диалоговом окне выберите процесс анализа и нажмите "Дамп GC GC". Вы можете при необходимости заморозить процесс или принудительно выполнить GC, прежде чем собирать снимок.

  3. Как только снимок сделан, нажмите "Закрыть".

Visual Studio и PerfView в основном полезны для агрегированного анализа. PerfView - это профилировщик пробоотбора, даже если он анализирует кучу, поэтому он иногда дает искаженное изображение того, как выглядит куча. Если вам нужно перейти к определенному объекту или получить абсолютную правду о всей картине, вам нужно начать использовать отладчик или CLR MD.

Ответ 14

Я предпочитаю dotmemory от Jetbrains

Ответ 15

Из Visual Studio 2015 рассмотрите возможность использования утилиты диагностики использования памяти из памяти, чтобы собирать и анализировать данные об использовании памяти.

Инструмент "Использование памяти" позволяет вам взять один или несколько снимков управляемой и собственной памяти, чтобы помочь понять влияние использования памяти на типы объектов.