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

StackOverflow https://stackoverflow.com/questions/134086

Вопрос

Я писал на C ++ в течение 10 лет.Я столкнулся с проблемами с памятью, но их можно было исправить, приложив разумные усилия.

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

        // It's 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

Мы использовали Ants Profiler Pro - Профилировщик Муравьев разработано Red Gate software в нашем проекте.Это действительно хорошо работает для всех.Приложения на основе NET language.

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

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

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).Это обеспечило очень значительный прирост производительности при ограничении обращений к базе данных и огромный выигрыш в объеме памяти.

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

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

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

От Как выявить утечки памяти в среде выполнения common language на Microsoft.com

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

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

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

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

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

У меня только что произошла утечка памяти в службе Windows, которую я исправил.

Сначала я попробовал MemProfiler - файл памяти.Я обнаружил, что это действительно сложно в использовании и совсем не удобно для пользователя.

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

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

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

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

Большие пушки - Средства отладки для Windows

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

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

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

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

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

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

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

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

Я предпочитаю точечная память от Jetbrains

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top