Каковы способы устранения утечек памяти в C#

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

Я исхожу из фона C++ и очень привык к запахам кода и шаблонам разработки. Я хочу узнать, как пахнет код в C#. Дай мне совет!

каковы наилучшие способы удаления?

Как вы можете выяснить, когда у вас есть "утечки памяти"?


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


большое спасибо.

10 ответов


C#, .NET Framework использует управляемую память, и все (но выделенные неуправляемые ресурсы) - это собранный мусор.

можно с уверенностью предположить, что управляемые типы всегда собирали мусор. Это включает arrays, classes и structures. Не стесняйтесь делать int[] stuff = new int[32]; и забыть об этом.

при открытии файла, подключения к базе данных или любого другого неуправляемого ресурса в классе реализуйте интерфейс IDisposable и в методе Dispose отмените выделение неуправляемого ресурс.

любой класс, который реализует IDisposable, должен быть явно закрыт или использоваться в (Я думаю, круто), используя блок like;

using (StreamReader reader = new StreamReader("myfile.txt"))
{
   ... your code here
}

здесь .NET будет утилизировать читателя, когда из области {}.


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

в частности, вещи, чтобы следить за:

  • много закрепления (устанавливает много ограничений на то, что может сделать GC)
  • много финализаторов (обычно они вам не нужны; замедляется GC)
  • статические события-простой способ сохранить много больших графов объектов в живых ; - p
  • события на недорогом объекте длинной жизни, который может видеть дорогой объект, который должен был быть очищен
  • "захваченные переменные" случайно сохраняя графики живыми

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


В общем, чем меньше вы беспокоитесь о распределении памяти в c#, тем лучше. Я бы оставил это профайлеру, чтобы сказать мне, когда у меня возникают проблемы с коллекцией.

вы не можете создавать утечки памяти в C# так же, как в C++. Сборщик мусора всегда будет "иметь вашу спину". Вы можете создавать объекты и хранить ссылки на них, даже если вы никогда их не используете. Это запах код искать.

другое, чем что:

  • имейте некоторое представление о том, как часто будет происходить сбор (по соображениям производительности)
  • не держите ссылки на объекты дольше, чем вам нужно
  • утилизируйте объекты, которые реализуют IDisposable, как только вы закончите с ними (используйте using синтаксис)
  • правильно использовать тег интерфейс IDisposable интерфейс

основными источниками утечек памяти, о которых я могу думать, являются:

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

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

  • взаимодействие с собственным кодом и невозможность его освобождения. Даже если вы используете управляемые оболочки, реализующие завершители, CLR часто не очищает их достаточно быстро, потому что не понимает объем памяти. Вы должны использовать шаблон using(IDisposable) {}

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

например: Объект Часы Объект Б Объект Б удаляется, если ссылка от A до B, не распорядились собственность ГК не properyly Dispose объекта. Поскольку обработчику событий все еще назначается GC, он не видит его как неиспользуемый ресурс.

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

есть некоторые большие программные приложения для управления памятью для мониторинга того, что происходит с кучей вашего приложения. Я нашел большую пользу от использования .NET Memory Profiler.

HTH


Я рекомендую использовать .NET профилировщик памяти

.NET Memory Profiler-это мощный инструмент для поиска утечек памяти и оптимизации использования памяти в программах, написанных на C#, VB.NET или любой другой язык .NET.

.NET Memory Profiler поможет вам:

  • просмотр в режиме реального времени памяти и информации о ресурсах
  • легко определить утечки памяти, собирая и сравнивая снимки .NET память!--12-->
  • найти экземпляры, которые не утилизируются
  • получить подробную информацию об использовании неуправляемых ресурсов
  • оптимизация использования памяти
  • исследовать проблемы с памятью в производственном коде
  • выполнить автоматическое тестирование памяти
  • получить информацию о родной

взгляните на их видео учебники:

http://memprofiler.com/tutorials/


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

Я хотел предложить некоторые дополнительные ресурсы; я нашел следующее бесценным при изучении деталей .NET GC и как устранить проблемы с памятью в приложениях .NET.

CLR через C# Джеффри Рихтер является отлично книги. Стоит цена покупки только для главы о GC и память.

этой блог (по Microsoft "ASP.NET Escalation Engineer") часто является моим источником для Советов и трюков по использованию WinDbg, SOS и для обнаружения определенных типов утечек памяти. Тесс даже разработала .NET debugging demos / labs, которая проведет вас через общие проблемы с памятью и как их распознавать и решать.

инструменты отладки для Windows (WinDbg, SOS, etc)


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


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

GC не может и не будет собирать объект, если есть какие-либо корневые ссылки на него, независимо от того, реализует ли он IDisposable или нет.

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


каковы наилучшие способы удаления вещей?

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

вероятно, лучший метод-реализовать и следовать шаблону IDisposable; и вызвать метод dispose для всех объектов, реализующих его.

оператор "using" - ваш лучший друг. Свободно положенный, он вызовет dispose для вас на объекты, реализующие IDisposable.