Какие способы решить утечки памяти в C # - PullRequest
10 голосов
/ 27 марта 2009

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

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

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

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


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


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

Ответы [ 10 ]

18 голосов
/ 27 марта 2009

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

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

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

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

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

Здесь .NET будет располагать читателя вне области {}.

11 голосов
/ 27 марта 2009

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

В частности, на что следует обратить внимание:

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

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

3 голосов
/ 27 марта 2009

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

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

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

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

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

Вы не можете создавать утечки памяти в C # так же, как в C ++. У сборщика мусора всегда будет «твоя спина». Что вы можете сделать, это создать объекты и хранить ссылки на них, даже если вы никогда не используете их. Это кодовый запах, за которым нужно следить.

Кроме этого:

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

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

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

CLR via C # Джеффри Рихтера - книга отлично . Стоит приобрести только за главу о ГХ и памяти.

Этот блог (от Microsoft «ASP.NET Escalation Engineer») часто служит моим источником рекомендаций и подсказок по использованию WinDbg, SOS и обнаружению утечек памяти определенных типов. Тесс даже разработала демоверсии / лаборатории для отладки .NET, которые помогут вам разобраться с распространенными проблемами с памятью и узнают, как их решить и решить.

Средства отладки для Windows (WinDbg, SOS и т. Д.)

1 голос
/ 27 марта 2009

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

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

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

  • Просмотр оперативной памяти и информации о ресурсах
  • Простое выявление утечек памяти путем сбора и сравнения снимков памяти .NET
  • Найти экземпляры, которые не расположены должным образом
  • Получение подробной информации об использовании неуправляемых ресурсов
  • Оптимизация использования памяти
  • Исследование проблем с памятью в рабочем коде
  • Выполнить автоматическое тестирование памяти
  • Получить информацию о собственной памяти

Посмотрите их видеоуроки:

http://memprofiler.com/tutorials/

1 голос
/ 27 марта 2009

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

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

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

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

НТН

0 голосов
/ 27 марта 2009

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

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

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

0 голосов
/ 27 марта 2009

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

0 голосов
/ 27 марта 2009

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

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

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

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

...