Хотя я понимаю серьезные последствия игры с этой функцией (или, по крайней мере, я так думаю), я не понимаю, почему она становится одной из тех вещей, которые уважаемые программисты никогда бы не использовали, даже те, кто даже не знает для чего это нужно.
Скажем, я разрабатываю приложение, в котором использование памяти сильно различается в зависимости от того, что делает пользователь. Жизненный цикл приложения можно разделить на два основных этапа: редактирование и обработка в реальном времени. На этапе редактирования предположим, что созданы миллиарды или даже триллионы объектов; некоторые из них маленькие, а некоторые нет, некоторые могут иметь финализаторы, а некоторые нет, и предположим, что их время жизни варьируется от нескольких миллисекунд до долгих часов. Затем пользователь решает перейти в режим реального времени. На этом этапе предположим, что производительность играет фундаментальную роль, и малейшее изменение в потоке программы может привести к катастрофическим последствиям. Затем создание объектов сокращается до минимально возможного за счет использования пулов объектов и тому подобного, но затем GC неожиданно звонит и отбрасывает все это, и кто-то умирает.
Вопрос: не стоит ли в этом случае вызывать GC.Collect () перед переходом на второй этап?
В конце концов, эти два этапа никогда не пересекаются друг с другом во времени, и вся оптимизация и статистика, которые мог бы собрать сборщик мусора, были бы здесь бесполезны ...
Примечание. Как отметили некоторые из вас, .NET может быть не лучшей платформой для такого приложения, но это выходит за рамки этого вопроса. Цель состоит в том, чтобы выяснить, может ли вызов GC.Collect () улучшить общее поведение / производительность приложения или нет. Мы все согласны с тем, что обстоятельства, при которых вы бы сделали это, крайне редки, но опять же, GC пытается угадать и делает это в большинстве случаев идеально, но это все еще о предположениях.
Спасибо.
Ответы:
Из блога Рико ...
Похоже, эта ситуация может подпадать под Правило № 2, вы знаете, что есть момент времени, когда многие старые объекты умерли, и это не повторяется. Однако не забывайте напутственные слова Рико.
Измеряйте, измеряйте, измеряйте.
источник
Если вы вызываете GC.Collect () в производственном коде, вы, по сути, заявляете, что знаете больше, чем авторы GC. Это может быть так. Однако обычно это не так, поэтому настоятельно не рекомендуется.
источник
malloc
имеет только очень простой интерфейс, и его реализации могут существенно различаться. Все зависит от того, какую проблему вы пытаетесь решить. Если быmalloc
было «достаточно хорошо», вам бы не понадобилось объединение буферов, не так ли? Разработка на C / C ++ изобилует примерами, в которых вы пытаетесь предугадать ОС / среду выполнения / библиотеки, потому что вам лучше известно (а иногда это действительно так). Многие приложения, критичные к производительности, полностью избегают использования распределителей системы / времени выполнения. Игры, используемые для предварительного выделения всей памяти при запуске (массивы постоянного размера и т. Д.).А как насчет того, чтобы использовать COM-объекты, такие как MS Word или MS Excel, из .NET? Без вызова
GC.Collect
после освобождения COM-объектов мы обнаружили, что экземпляры приложения Word или Excel все еще существуют.На самом деле код, который мы используем:
Так что это неправильное использование сборщика мусора? Если да, то как заставить умереть объекты взаимодействия? Кроме того, если он не предназначен для использования , как это, почему в
GC
«SCollect
метод дажеPublic
?источник
Что ж, GC - одна из тех вещей, с которыми у меня есть отношения любви / ненависти. Мы ломали его в прошлом через VistaDB и писали об этом в блогах. Они исправили это, но чтобы получить от них исправления в подобных вещах, требуется ДОЛГОЕ время.
Сборщик мусора сложен, и универсальный подход очень и очень сложно реализовать на чем-то столь большом. MS проделала довольно хорошую работу, но иногда можно обмануть GC.
В общем, вам не следует добавлять,
Collect
если вы не знаете, что вы только что сбросили тонну памяти, и она перейдет в кризис среднего возраста, если GC не очистит ее сейчас.Вы можете испортить всю машину серией плохих
GC.Collect
заявлений. Необходимость в операторе сбора почти всегда указывает на более серьезную основную ошибку. Утечка памяти обычно связана со ссылками и непониманием того, как они работают. Или использованиеIDisposable
on-объектов, которые в этом не нуждаются, и значительно увеличивают нагрузку на GC.Внимательно следите за процентом времени, проведенным в GC, по счетчикам производительности системы. Если вы видите, что ваше приложение использует 20% или более своего времени в сборщике мусора, у вас серьезные проблемы с управлением объектами (или ненормальный шаблон использования). Вы хотите всегда минимизировать время, которое тратит сборщик мусора, потому что это ускорит работу всего вашего приложения.
Также важно отметить, что GC на серверах отличается от рабочих станций. Я видел ряд небольших трудных для отслеживания проблем, когда люди не тестировали их обоих (или даже не знали, что их двое).
И чтобы мой ответ был как можно более полным, вам также следует протестировать в Mono, если вы ориентируетесь на эту платформу. Поскольку это совершенно другая реализация, могут возникнуть совершенно другие проблемы, чем в реализации MS.
источник
Бывают ситуации, когда это полезно, но в целом этого следует избегать. Вы можете сравнить это с GOTO или ездой на мопеде: вы делаете это, когда вам нужно, но не говорите об этом своим друзьям.
источник
По моему опыту, никогда не было целесообразно вызывать GC.Collect () в производственном коде. При отладке да, у него есть преимущества, помогающие выявить потенциальные утечки памяти. Я предполагаю, что моя основная причина в том, что сборщик мусора был написан и оптимизирован программистами намного умнее, чем я, и если я дойду до точки, в которой, как мне кажется, мне нужно вызвать GC.Collect (), это признак того, что я сбился с пути где-то. В вашей ситуации это не похоже на то, что у вас на самом деле проблемы с памятью, просто вы беспокоитесь о том, какую нестабильность коллекция принесет вашему процессу. Видя, что он не очищает объекты, которые все еще используются, и что он очень быстро адаптируется как к возрастающим, так и к снижению требований, я думаю, вам не придется об этом беспокоиться.
источник
Одна из главных причин для вызова GC.Collect () - это когда вы только что выполнили важное событие, которое создает много мусора, такого как то, что вы описываете. Вызов GC.Collect () здесь может быть хорошей идеей; в противном случае GC может не понять, что это было «разовое» событие.
Конечно, вы должны профилировать это и убедиться в этом сами.
источник
Что ж, очевидно, вам не следует писать код с требованиями реального времени на языках со сборкой мусора не в реальном времени.
В случае с четко определенными этапами нет проблем с запуском сборщика мусора. Но это случается крайне редко. Проблема в том, что многие разработчики попытаются использовать это для устранения проблем в стиле карго-культа, а добавление его без разбора вызовет проблемы с производительностью.
источник
Вызов GC.Collect () заставляет CLR выполнить обход стека, чтобы увидеть, действительно ли каждый объект может быть освобожден путем проверки ссылок. Это повлияет на масштабируемость, если количество объектов велико, а также, как известно, слишком часто запускает сборку мусора. Доверяйте среде CLR и позвольте сборщику мусора запускаться при необходимости.
источник
На самом деле, я не думаю, что вызывать GC.Collect - плохая практика.
Могут быть случаи, когда нам это понадобится. Например, у меня есть форма, которая запускает поток, который, в свою очередь, открывает различные таблицы в базе данных, извлекает содержимое из поля BLOB во временный файл, шифрует файл, затем считывает файл в двоичный поток и обратно в BLOB поле в другой таблице.
Вся операция занимает довольно много памяти, и нет уверенности в количестве строк и размере содержимого файла в таблицах.
Раньше я часто получал исключение OutofMemory, и я подумал, что было бы разумно периодически запускать GC.Collect на основе переменной счетчика. Я увеличиваю счетчик, и по достижении заданного уровня вызывается сборщик мусора для сбора любого мусора, который мог образоваться, и для восстановления памяти, потерянной из-за непредвиденных утечек памяти.
После этого, я думаю, он работает хорошо, по крайней мере, не исключение !!!
Звоню следующим образом:
источник
В .net время, необходимое для выполнения сборки мусора, гораздо сильнее зависит от количества материала, который не является мусором, чем от количества того, что есть. Действительно, если объект не переопределяет
Finalize
(явно или через деструктор C #), он является цельюWeakReference
, не находится в куче больших объектов или не является особенным каким-либо другим образом, связанным с gc, единственное, что идентифицирует память, в которой он находится поскольку объект является существованием корневых ссылок на него. В противном случае работа сборщика мусора аналогична тому, как брать из здания все ценное и взрывать здание, строить новое на месте старого и помещать в него все ценные предметы. Усилия, необходимые для взрыва здания, полностью не зависят от количества мусора внутри него.Следовательно, вызов
GC.Collect
может увеличить общий объем работы, которую должна выполнять система. Это задержит появление следующей коллекции, но, вероятно, сразу же выполнит столько же работы, сколько потребовалось бы для следующей коллекции, когда она возникла; в момент, когда должна была произойти следующаяGC.Collect
сборка, общее время, потраченное на сборку, будет примерно таким же, как не было вызвано, но в системе будет накоплен некоторый мусор, из-за чего последующая сборка потребуется раньше, чемGC.Collect
не было был вызван.Я вижу
GC.Collect
действительно полезные моменты , когда нужно либо измерить использование памяти некоторым кодом (поскольку цифры использования памяти действительно значимы только после коллекции), либо определить, какой из нескольких алгоритмов лучше (вызов GC.Collect () перед запуском каждого из нескольких фрагментов кода может помочь обеспечить согласованное базовое состояние). Есть несколько других случаев, когда кто-то может знать то, чего не знает GC, но, если вы не пишете однопоточную программу, никто не может узнать, чтоGC.Collect
вызов, который поможет структурам данных одного потока избежать «кризиса середины жизни». "не привело бы к" кризисам среднего возраста "в данных других потоков, которых в противном случае можно было бы избежать.источник
Создание образов в цикле - даже если вы вызываете dispose, память не восстанавливается. Сбор мусора каждый раз. Я перешел с 1,7 ГБ памяти в моем приложении для обработки фотографий до 24 МБ, и производительность отличная.
Есть абсолютно время, когда вам нужно вызвать GC.Collect.
источник
Dispose
это не должно освободить управляемую память. Похоже, вы не знаете, как работает модель памяти в .NET.У нас была аналогичная проблема с сборщиком мусора, который не собирает мусор и не освобождает память.
В нашей программе мы обрабатывали таблицы Excel небольшого размера с помощью OpenXML. Таблицы содержали от 5 до 10 "листов" примерно с 1000 строками по 14 столбцов.
Программа в 32-битной среде (x86) вылетела бы с ошибкой «нехватка памяти». Нам удалось запустить его в среде x64, но нам нужно было лучшее решение.
Мы нашли один.
Вот несколько упрощенных фрагментов кода того, что не сработало и что сработало, когда дело доходит до явного вызова сборщика мусора для освобождения памяти от удаленных объектов.
Вызов GC из подпрограммы не работал. Память никогда не возвращалась ...
Перемещая вызов GC за пределы подпрограммы, мусор был собран, а память была освобождена.
Надеюсь, это поможет другим, которые разочарованы сборкой мусора .NET, когда кажется, что она игнорирует вызовы
GC.Collect()
.Пол Смит
источник
Нет ничего плохого в явном вызове коллекции. Некоторым людям просто действительно хочется верить, что если это услуга, предоставляемая поставщиком, не сомневайтесь в этом. Да, и все эти случайные зависания вашего интерактивного приложения в неподходящие моменты? В следующей версии будет лучше!
Разрешить фоновому процессу заниматься манипуляциями с памятью - значит не заниматься этим самим, правда. Но логически это не означает, что нам лучше не заниматься этим самостоятельно ни при каких обстоятельствах. ГХ оптимизирован для большинства случаев. Но логически это не означает, что он оптимизирован во всех случаях.
Вы когда-нибудь отвечали на открытый вопрос, например, «какой алгоритм сортировки лучший»? В таком случае не прикасайтесь к ГХ. Для тех из вас, кто спрашивал об условиях или давал ответы типа «в этом случае», вы можете перейти к изучению GC и того, когда его активировать.
Должен сказать, у меня были зависания приложений в Chrome и Firefox, которые меня чертовски расстраивали, и даже тогда в некоторых случаях память беспрепятственно растет - если бы только они научились вызывать сборщик мусора - или дали мне кнопку, чтобы, когда я начинал читать текст страницы, я мог нажать на нее и, таким образом, не зависать в течение следующих 20 минут.
источник
Я думаю, что вы правы относительно сценария, но я не уверен насчет API.
Microsoft говорит, что в таких случаях вам следует добавить нехватку памяти в качестве подсказки для GC, что он должен вскоре выполнить сбор.
источник
Что с этим не так? Тот факт, что вы подвергаете сомнению сборщик мусора и распределитель памяти, которые между ними имеют гораздо большее представление о фактическом использовании памяти вашим приложением во время выполнения, чем вы.
источник
Желание вызвать GC.Collect () обычно пытается скрыть ошибки, которые вы сделали где-то еще!
Было бы лучше, если бы вы нашли место, где забыли выбросить ненужные вещи.
источник
В итоге вы можете профилировать приложение и посмотреть, как эти дополнительные коллекции влияют на вещи. Я бы посоветовал держаться подальше от этого, если вы не собираетесь профилировать. Сборщик мусора разработан так, чтобы заботиться о себе сам, и по мере развития среды выполнения они могут повысить эффективность. Вы не хотите, чтобы вокруг висела куча кода, которая может испортить работу и не сможет воспользоваться этими улучшениями. Есть аналогичный аргумент в пользу использования foreach вместо for, поскольку в будущем в foreach могут быть добавлены скрытые улучшения, и ваш код не должен изменяться, чтобы воспользоваться этим преимуществом.
источник
Сама .NET Framework никогда не предназначалась для работы в среде реального времени. Если вам действительно нужна обработка в реальном времени, вы должны либо использовать встроенный язык реального времени, который не основан на .NET, либо использовать .NET Compact Framework, работающий на устройстве Windows CE.
источник
Худшее, что это может сделать, - это заставить вашу программу ненадолго зависнуть. Так что, если вас это устраивает, сделайте это. Обычно это не требуется для толстого клиента или веб-приложений, в основном взаимодействующих с пользователем.
Я обнаружил, что иногда программы с длительными потоками или пакетные программы получают исключение OutOfMemory, даже если они правильно удаляют объекты. Один из них, который я помню, касался обработки транзакций в базе данных в рамках бизнеса; другой - это процедура индексации в фоновом потоке толстого клиентского приложения.
В обоих случаях результат был прост: постоянное отсутствие GC.Collect, нехватка памяти; GC.Collect, безупречная работа.
Я несколько раз пробовал решить проблемы с памятью, но безуспешно. Я вынул.
Короче говоря, не вставляйте его, если у вас нет ошибок. Если вы вставили его, и это не решило проблему с памятью, выньте его обратно. Не забудьте протестировать в режиме Release и сравнить яблоки с яблоками.
Единственный раз, когда что-то может пойти не так, это когда вы станете относиться к этому моралистически. Это не проблема ценностей; многие программисты умерли и попали прямо в рай со множеством ненужных GC.Collects в своем коде, который их пережил.
источник