Лучшая практика для принудительного сбора мусора в C # - PullRequest
114 голосов
/ 24 октября 2008

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

Ответы [ 15 ]

110 голосов
/ 24 октября 2008

Лучшей практикой является не форсировать сборку мусора.

Согласно MSDN:

"Можно заставить мусор сбор по вызову Collect, но в большинстве случаев это должно быть избегать, потому что это может создать проблемы с производительностью. «

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

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

Эта ссылка содержит несколько полезных практических советов относительно освобождения памяти / сборки мусора и т. Д .:

http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

30 голосов
/ 24 сентября 2009

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

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

Однако в некоторых пакетных типах обработки вы знаете больше, чем GC. Например. рассмотрим приложение, которое.

  • Дан список имен файлов в командной строке
  • Обрабатывает один файл, а затем записывает результат в файл результатов.
  • При обработке файла создается много связанных объектов, которые невозможно собрать до завершения обработки файла (например, дерево разбора)
  • Не сохраняет много состояния между файлами, которые он обработал .

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

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

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

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

См. Также « Показательные выступления Рико Мариани »

28 голосов
/ 02 ноября 2008

Посмотрите на это так - эффективнее ли выбрасывать кухонный мусор, когда мусорное ведро заполнено на 10%, или дать ему заполниться, прежде чем вынимать его?

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

Конечно, вы можете столкнуться с ситуацией, когда в ближайшее время вы ничего не добавите в мусорное ведро - скажем, если вы собираетесь в отпуск. Тогда было бы неплохо выбросить мусор перед выходом.

Это МОЖЕТ быть один раз, когда может помочь форсирование GC - если ваша программа простаивает, используемая память не собирается сборщиком мусора, потому что нет выделений.

20 голосов
/ 02 ноября 2008

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

15 голосов
/ 06 ноября 2008

Есть несколько общих рекомендаций в программировании, которые являются абсолютными. В половине случаев, когда кто-то говорит «ты делаешь это неправильно», он просто излагает определенное количество догм. В Си раньше это был страх перед такими вещами, как самоизменяющийся код или потоки, в языках GC это заставляет GC или, наоборот, мешает работе GC.

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

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

13 голосов
/ 24 октября 2008

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

9 голосов
/ 21 сентября 2012

Один случай, с которым я недавно столкнулся, который требовал ручных вызовов к GC.Collect(), был при работе с большими объектами C ++, которые были обернуты в крошечные управляемые объекты C ++, к которым в свою очередь обращались из C #.

Сборщик мусора так и не был вызван, потому что объем используемой управляемой памяти был незначительным, но объем используемой неуправляемой памяти был огромен. Ручной вызов Dispose() для объектов потребует, чтобы я отслеживал, когда объекты больше не нужны сам, тогда как вызов GC.Collect() очистит все объекты, на которые больше не ссылаются .....

9 голосов
/ 24 октября 2008

Не уверен, что это лучший метод, но при работе с большим количеством изображений в цикле (т. Е. При создании и утилизации большого количества объектов Graphics / Image / Bitmap) я регулярно разрешаю GC.Collect.

Мне кажется, я где-то читал, что ГХ работает только тогда, когда программа (в основном) простаивает, а не в середине интенсивного цикла, так что это может выглядеть как область, в которой ручной ГХ может иметь смысл.

7 голосов
/ 24 октября 2008

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

  1. Есть ли в вашем коде что-то, что объявляет элементы в большем объеме, чем необходимо
  2. действительно ли слишком велико использование памяти
  3. Сравните производительность до и после использования GC.Collect (), чтобы увидеть, действительно ли это помогает.
5 голосов
/ 02 ноября 2008

Предположим, что ваша программа не имеет утечки памяти, объекты накапливаются и не могут быть GC-ed в Gen 0, потому что: 1) На них давным-давно ссылаются, так что попадайте в Gen1 и Gen2; 2) Это большие объекты (> 80К), поэтому попадайте в LOH (куча больших объектов). И LOH не делает сжатие, как в Gen0, Gen1 и Gen2.

Проверьте счетчик производительности ".NET Memory", вы можете увидеть, что проблема 1) действительно не проблема. Как правило, каждые 10 Gen0 GC активируют 1 Gen1 GC, а каждые 10 Gen1 GC активируют 1 Gen2 GC. Теоретически, GC1 и GC2 никогда не могут быть GC-ed, если на GC0 нет давления (если использование памяти программы действительно подключено). Со мной этого никогда не случится.

Для проблемы 2) вы можете проверить счетчик производительности «.NET Memory», чтобы убедиться, что LOH становится раздутым. Если это действительно проблема вашей проблемы, возможно, вы можете создать пул больших объектов, как предлагает этот блог http://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx.

...