Общий совет, что вы не должны звонить GC.Collect
из своего кода, но каковы исключения из этого правила?
Я могу думать только о нескольких очень специфических случаях, когда имеет смысл форсировать сборку мусора.
Один пример, который приходит на ум, - это служба, которая периодически просыпается, выполняет какую-то задачу, а затем спит в течение длительного времени. В этом случае может быть хорошей идеей принудительно выполнить сбор, чтобы предотвратить удержание процесса, который вскоре будет бездействующим, большего объема памяти, чем необходимо.
Есть ли другие случаи, когда можно звонить GC.Collect
?
c#
.net
garbage-collection
Брайан Расмуссен
источник
источник
Ответы:
Если у вас есть веские основания полагать, что значительный набор объектов, особенно тех, которые, как вы подозреваете, относятся к поколениям 1 и 2, теперь имеют право на сборку мусора, и сейчас самое подходящее время для сбора с точки зрения небольшого снижения производительности. ,
Хороший пример этого - если вы только что закрыли большую форму. Вы знаете, что теперь все элементы управления пользовательским интерфейсом могут быть собраны мусором, и очень короткая пауза, когда форма закрыта, вероятно, не будет заметна пользователю.
ОБНОВЛЕНИЕ 2.7.2018
Начиная с .NET 4.5 - есть
GCLatencyMode.LowLatency
иGCLatencyMode.SustainedLowLatency
. При входе в любой из этих режимов и выходе из него рекомендуется принудительно выполнить полный GCGC.Collect(2, GCCollectionMode.Forced)
.Начиная с .NET 4.6 - существует
GC.TryStartNoGCRegion
метод (используется для установки значения только для чтенияGCLatencyMode.NoGCRegion
). Это может само по себе выполнить полную блокировку сборки мусора в попытке освободить достаточно памяти, но, учитывая, что мы запрещаем сборку мусора в течение некоторого времени, я бы сказал, что это также хорошая идея, чтобы выполнить полную сборку мусора до и после.Источник: инженер Microsoft Бен Уотсон: написание высокопроизводительного кода .NET , 2-е изд. 2018.
Видеть:
источник
GC.Collect
вы в основном сообщаете сборщику мусора, что вы знаете, лучше, чем это для разнообразия. Почему тебе не нравится пример?GC.Collect()
запросит, чтобы GC выполнил полный сбор. Если вы знаете, что только что сделали много ранее долгоживущих объектов, подходящих для сбора мусора, и считаете, что пользователь с меньшей вероятностью заметит небольшую паузу сейчас, чем позже, кажется вполне разумным думать, что сейчас лучше время, чтобы побудить коллекцию, чем позволить этому произойти позже.Я использую
GC.Collect
только при написании грубых тестов производительности / профилировщика; т.е. у меня есть два (или более) блока кода для тестирования - что-то вроде:Так что
TestA()
иTestB()
бегите с максимально похожим состоянием - т.е.TestB()
не забейте только потому, чтоTestA
оставили его очень близко к переломному моменту.Классическим примером может быть простой консольный exe (
Main
метод, достаточно сортировочный, например, для публикации здесь), который показывает разницу между конкатенацией циклических строк иStringBuilder
.Если мне нужно что-то точное, то это будут два совершенно независимых теста, но часто этого достаточно, если мы просто хотим минимизировать (или нормализовать) GC во время тестов, чтобы получить грубое представление о поведении.
Во время производства кода? Я еще не использовал это ;-p
источник
В большинстве случаев лучше не форсировать сборку мусора. (Каждая система, над которой я работал, имела принудительную сборку мусора, подчеркивала проблемы, которые в случае ее устранения устраняли бы необходимость принудительной сборки мусора и значительно ускоряли работу системы.)
Есть несколько случаев, когда вы знаете больше об использовании памяти, чем сборщик мусора. Это вряд ли может быть правдой в многопользовательском приложении или сервисе, который отвечает более чем на один запрос за раз.
Однако в некоторых типах обработки вы знаете больше, чем GC. Например, рассмотреть приложение, которое.
Вы можете быть в состоянии сделать случай (после тщательного) тестирования , что вы должны заставить полный сбор мусора после того как вы обрабатывать каждый файл.
В других случаях это служба, которая просыпается каждые несколько минут для обработки некоторых элементов и не сохраняет состояния, пока она спит . Затем принуждая полную коллекцию непосредственно перед сном может быть полезным.
Я бы предпочел иметь API для сборки мусора, когда я мог бы дать ему подсказки об этом типе вещей, не заставляя себя собирать GC.
См. Также « Производительность Рико Мариани »
источник
Один случай, когда вы пытаетесь выполнить модульный тест кода, который использует WeakReference .
источник
В больших системах 24/7 или 24/6 - системах, которые реагируют на сообщения, запросы RPC или которые непрерывно опрашивают базу данных или обрабатывают - полезно иметь способ выявления утечек памяти. Для этого я склонен добавлять в приложение механизм, который временно приостанавливает любую обработку, а затем выполняет полную сборку мусора. Это переводит систему в состояние покоя, где оставшаяся память либо является законно долгоживущей памятью (кэшами, конфигурацией и т. Д.), Либо «протекает» (объекты, которые не ожидаются или не желают быть укорененными, но на самом деле есть).
Наличие этого механизма значительно упрощает профилирование использования памяти, поскольку отчеты не будут затуманены шумом от активной обработки.
Чтобы убедиться, что вы получили весь мусор, вам нужно выполнить две коллекции:
Поскольку первая коллекция вызовет завершение любых объектов с финализаторами (но не сборщиками мусора эти объекты). Второй сборщик мусора будет собирать эти завершенные объекты.
источник
Вы можете вызвать GC.Collect (), когда узнаете что-то о природе приложения, которого не знает сборщик мусора. Заманчиво думать, что, как автор, это очень вероятно. Однако правда в том, что GC представляет собой довольно хорошо написанную и протестированную экспертную систему, и редко вы узнаете что-либо о низкоуровневых путях кода, которых нет.
Лучший пример, который я могу вспомнить, где у вас может быть какая-то дополнительная информация, - это приложение, которое циклически переключается между периодами простоя и очень занятыми периодами. Вы хотите максимально возможную производительность в периоды занятости и, следовательно, хотите использовать время простоя для некоторой очистки.
Тем не менее, в большинстве случаев GC достаточно умен, чтобы сделать это в любом случае.
источник
Как решение для фрагментации памяти. Я получал исключения из памяти при записи большого количества данных в поток памяти (чтение из сетевого потока). Данные были записаны в 8K кусках. После достижения 128M было исключение, хотя было много доступной памяти (но она была фрагментирована). Вызов GC.Collect () решил проблему. Я смог справиться с 1G после исправления.
источник
Взгляните на эту статью Рико Мариани. Он дает два правила, когда вызывать GC.Collect (правило 1: «Не надо»):
Когда вызывать GC.Collect ()
источник
Один из случаев, когда почти необходимо вызвать GC.Collect (), - это автоматизация Microsoft Office через Interop. COM-объекты для Office не любят автоматически освобождаться и могут привести к тому, что экземпляры продукта Office будут занимать очень большие объемы памяти. Я не уверен, если это проблема или дизайн. В интернете много постов на эту тему, поэтому я не буду вдаваться в подробности.
При программировании с использованием Interop каждый отдельный COM-объект должен быть освобожден вручную, обычно с использованием Marshal.ReleseComObject (). Кроме того, вызов Garbage Collection вручную может помочь немного «очиститься». Вызов следующего кода, когда вы закончите с объектами Interop, кажется, очень помогает:
По моему личному опыту, использование комбинации ReleaseComObject и ручного вызова сборки мусора значительно сокращает использование памяти продуктами Office, в частности Excel.
источник
Я делал некоторые тесты производительности на массив и список:
и я получил
OutOfMemoryException
в методе GetSomeNumbers_Enumerable_Range единственный выход - освободить память:источник
В вашем примере, я думаю, что вызов GC.Collect не проблема, а скорее проблема дизайна.
Если вы собираетесь просыпаться с интервалами (заданными временами), то ваша программа должна быть создана для одного выполнения (выполнить задачу один раз), а затем завершиться. Затем вы настраиваете программу как запланированное задание для запуска через запланированные интервалы.
Таким образом, вам не нужно беспокоиться о вызове GC.Collect (что вам следует делать редко, если вообще нужно).
При этом у Рико Мариани есть отличный пост на эту тему, который можно найти здесь:
http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx
источник
Одно полезное место для вызова GC.Collect () - это модульный тест, когда вы хотите убедиться, что вы не создаете утечку памяти (например, если вы что-то делаете с WeakReferences или ConditionalWeakTable, динамически генерируемым кодом и т. Д.).
Например, у меня есть несколько тестов, таких как:
Можно утверждать, что использование WeakReferences само по себе является проблемой, но кажется, что если вы создаете систему, основанную на таком поведении, то вызов GC.Collect () является хорошим способом проверки такого кода.
источник
Запись Скотта Холдена в блоге о том, когда (а когда нет) вызывать GC.Collect , специфична для .NET Compact Framework , но правила обычно применяются ко всем управляемым разработкам.
источник
Краткий ответ: никогда!
источник
источник
Есть ситуации, когда это лучше, чем потом сожалеть.
Здесь одна ситуация.
Можно написать неуправляемую DLL в C #, используя переписывание IL (потому что есть ситуации, когда это необходимо).
Теперь предположим, например, что DLL создает массив байтов на уровне класса - потому что многие из экспортируемых функций нуждаются в таком доступе. Что происходит, когда DLL выгружается? В этот момент автоматически вызывается сборщик мусора? Я не знаю, но, будучи неуправляемой DLL, вполне возможно, что GC не вызывается. И это было бы большой проблемой, если бы его не называли. Когда DLL выгружается, сборщик мусора тоже будет - так кто же будет отвечать за сбор любого возможного мусора и как они это сделают? Лучше использовать сборщик мусора в C #. Иметь функцию очистки (доступную для клиента DLL), в которой переменные уровня класса имеют значение null и вызывается сборщик мусора.
Береженого Бог бережет.
источник
Я все еще не уверен в этом. Я работаю с 7 лет на сервере приложений. Наши большие установки используют оперативную память объемом 24 ГБ. Его многопоточный и ВСЕ вызовы для GC.Collect () столкнулись с действительно ужасными проблемами производительности.
Многие Сторонние Компоненты использовали GC.Collect (), когда они думали, что это было разумно сделать это прямо сейчас. Таким образом, простая группа Excel-отчетов блокировала сервер приложений для всех потоков несколько раз в минуту.
Нам пришлось провести рефакторинг всех сторонних компонентов, чтобы удалить вызовы GC.Collect (), и после этого все работало нормально.
Но я также использую Серверы на Win32, и здесь я начал активно использовать GC.Collect () после получения исключения OutOfMemoryException.
Но я также довольно неуверен в этом, потому что я часто замечал, что когда я получаю OOM на 32-битной системе, и я снова пытаюсь запустить ту же операцию, не вызывая GC.Collect (), она просто работает нормально.
Одна вещь, которая меня интересует, это само исключение OOM ... Если бы я написал .Net Framework и не смог бы выделить блок памяти, я бы использовал GC.Collect (), дефрагментировал память (??), попробуйте снова , и если я все еще не могу найти свободный блок памяти, то я бы выбросил OOM-Exception.
Или, по крайней мере, сделайте это поведение настраиваемым параметром из-за недостатков производительности, связанных с GC.Collect.
Теперь в моем приложении много такого кода, чтобы «решить» проблему:
(Обратите внимание, что поведение Thread.Sleep () действительно специфично для приложения, поскольку мы запускаем службу кэширования ORM, и службе требуется некоторое время для освобождения всех кэшированных объектов, если объем оперативной памяти превышает некоторые предопределенные значения. Поэтому он ожидает несколько секунд в первый раз, и увеличилось время ожидания при каждом появлении OOM.)
источник
GC.Collect
. Так как он имеет широкое влияние на приложение, это должно делать только приложение (если вообще).If i would have written the .Net Framework, and i can't alloc a memory block, i would use GC.Collect(),
- Я думаю, что они уже делают это - я видел признаки того, что один из внутренних триггеров GC - определенные сбои в распределении памяти.Вам следует избегать использования GC.Collect (), так как он очень дорогой. Вот пример:
РЕЗУЛЬТАТ ИСПЫТАНИЯ: ИСПОЛЬЗОВАНИЕ ЦП 12%
Когда вы переходите на это:
РЕЗУЛЬТАТ ТЕСТА: ИСПОЛЬЗОВАНИЕ ЦП 2-3%
источник
Другая причина заключается в том, что SerialPort открыт на COM-порту USB, а затем USB-устройство отключено. Поскольку SerialPort был открыт, ресурс содержит ссылку на ранее подключенный порт в системном реестре. Системный реестр будет содержать устаревшие данные , поэтому список доступных портов будет неправильным. Поэтому порт должен быть закрыт.
Вызов SerialPort.Close () для порта вызывает Dispose () для объекта, но он остается в памяти до тех пор, пока сборка мусора не будет фактически запущена, в результате чего реестр останется устаревшим, пока сборщик мусора не решит освободить ресурс.
С https://stackoverflow.com/a/58810699/8685342 :
источник
Это не имеет отношения к вопросу, но для XSLT-преобразований в .NET (XSLCompiledTranform) у вас может не быть выбора. Другим кандидатом является контроль MSHTML.
источник
Если вы используете версию .net менее 4.5, сбор вручную может быть неизбежен (особенно если вы имеете дело со многими «большими объектами»).
эта ссылка описывает почему:
https://blogs.msdn.microsoft.com/dotnet/2011/10/03/large-object-heap-improvements-in-net-4-5/
источник
одна хорошая причина для вызова GC - на небольших компьютерах ARM с небольшим объемом памяти, таких как Raspberry PI (работает с моно). Если нераспределенные фрагменты памяти используют слишком много системной оперативной памяти, ОС Linux может работать нестабильно. У меня есть приложение, где я должен вызывать GC каждую секунду (!), Чтобы избавиться от проблем переполнения памяти.
Другим хорошим решением является удаление объектов, когда они больше не нужны. К сожалению, во многих случаях это не так просто.
источник
Так как есть куча малых объектов (SOH) и куча больших объектов (LOH)
Мы можем вызвать GC.Collect (), чтобы очистить объект отмены ссылки в SOP и переместить живой объект в следующее поколение.
В .net4.5 мы также можем сжать LOH, используя большой режим сравнения объектов
источник
Если вы создаете много новых
System.Drawing.Bitmap
объектов, сборщик мусора не очищает их. В конечном итоге GDI + решит, что вам не хватает памяти, и выдаст исключение «Параметр не действителен». ЗвонкиGC.Collect()
так часто (не слишком часто!), Кажется, решают эту проблему.источник