Каков риск вызова GC.Collect ()? [Дубликат]

Swift 3.0

Очень простое решение здесь

Чтобы сменить страницу (UIViewController) из UIViewController, сначала получите экземпляр Parent ViewController (который будет UIPageViewController), а затем установите его текущий ViewController

В моем случае у меня есть UIPageViewController с именем «UserDetailsPVC» и он содержит 4 страницы (UIViewControllers), которые выглядят следующим образом

  PageOneVC:UIViewController
  PageTwoVC:UIViewController
  PageThreeVC:UIViewController
  PageFourVC:UIViewController

В UIPageViewController можно определить массив страниц

 var pages:[UIViewController] = [
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageOneVC"),
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageTwoVC"),
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageThreeVC"),
        UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PageFourVC")
]

Теперь, чтобы изменить страницу UIPageViewController с любого из UIViewController

    // get parent view controller
    let parentVC = self.parent as! UserDetailsPVC

    // change page of PageViewController
    parentVC.setViewControllers([parentVC.pages[1]], direction: .forward, animated: true, completion: nil)
110
задан Echostorm 24 October 2008 в 14:49
поделиться

17 ответов

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

Согласно MSDN:

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

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

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

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

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

108
ответ дан Mark Ingram 18 August 2018 в 06:57
поделиться
  • 1
    Кроме того, вы можете установить различные параметры msgid.microsoft.com/en-us/library/bb384202.aspx LatencyMode] – David d C e Freitas 8 July 2011 в 16:18
  • 2
    Если ваши объекты указывают на неуправляемую память, вы можете сообщить коллекционеру мусора через GC.AddMemoryPressure Api ( msdn.microsoft.com/en-us/library/… ). Это дает сборщику мусора дополнительную информацию о вашей системе, не мешая алгоритмам сбора. – Govert 1 February 2012 в 20:51
  • 3
    +1: * посмотрите на использование инструкции «using» & quot; и интерфейс IDisposable. * Я бы даже не подумал о принуждении, кроме как в крайнем случае - хороший совет (читайте как «отказ от ответственности»). Тем не менее, я вынуждаю сбор в единичном тесте имитировать потерю активной ссылки в фоновом режиме - в конечном счете бросая TargetOfInvocationNullException. – IAbstract 1 April 2012 в 16:30

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

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

9
ответ дан fabspro 18 August 2018 в 06:57
поделиться
  • 1
    Лучшим способом решения этого является вызов GC.AddMemoryPressure (ApproximateSizeOfUnmanagedResource) в конструкторе, а затем GC.RemoveMemoryPressure(addedSize) в финализаторе. Таким образом сборщик мусора будет запускаться автоматически, принимая во внимание размер неуправляемых структур, которые могут быть собраны. [Д0] stackoverflow.com/questions/1149181/… – HugoRune 21 January 2013 в 11:57
  • 2
    И еще лучший способ решить проблему - это фактически вызвать Dispose (), который вы все равно должны делать. – fabspro 14 March 2014 в 16:12
  • 3
    Лучший способ - использовать структуру «Использование». Попробуйте / Наконец. – TamusJRoyce 5 June 2015 в 16:49

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

30
ответ дан Ian Ringrose 18 August 2018 в 06:57
поделиться
  • 1
    Или просто перед открытием большого смежного объекта, который показал историю сбоев, и не дает эффективного разрешения для увеличения его детализации. – crokusek 25 June 2013 в 01:05
  • 2
    Аналогия: Playschool (система) хранит карандаши (ресурсы). В зависимости от количества детей (задач) и нехватки цветов учитель (.Net) решает, как распределять и делиться среди детей. Когда запрашивается редкий цвет, учитель может выделять из пула или искать тот, который не используется. Учитель имеет право периодически собирать неиспользованные карандаши (сбор мусора), чтобы сохранить порядок вещей (оптимизировать использование ресурсов). Как правило, родитель (программист) не может предопределять оптимальную политику классного карандаша. Плановый сон одного ребенка вряд ли станет хорошим моментом, чтобы помешать раскраски других детей. – AlanK 30 December 2017 в 22:37
  • 3
    @AlanK, мне это нравится, когда дети идут домой в течение дня, это очень хорошее время для помощника учителей, чтобы сделать хороший порядок, без того, чтобы дети не мешали. (Недавние системы, над которыми я работал, только что перезапустили сервисный процесс, в такое время усиливают принудительное использование GC.) – Ian Ringrose 31 December 2017 в 00:42

Большие объекты выделяются на LOH (куча больших объектов), а не на gen 0. Если вы говорите, что они не получают сбор мусора с генератором 0, вы правы. Я считаю, что они собираются только тогда, когда происходит полный цикл GC (поколения 0, 1 и 2).

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

Трудно сказать, собираться или нет, и при каких обстоятельствах. Я использовал GC.Collect () после удаления диалоговых окон / форм с многочисленными элементами управления и т. Д. (Потому что к моменту, когда форма и ее элементы управления заканчиваются в гене 2 из-за создания множества экземпляров бизнес-объектов / загрузки многих данных - нет крупные объекты, очевидно), но на самом деле не заметили никаких положительных или отрицательных эффектов в долгосрочной перспективе, сделав это.

4
ответ дан liggett78 18 August 2018 в 06:57
поделиться

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

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

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

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

28
ответ дан Maxam 18 August 2018 в 06:57
поделиться
  • 1
    Если бы у вас был ребенок, который бы умер, если вы оставите его на более чем минуту, и у вас будет только одна минута, чтобы справиться с мусором, тогда вам нужно делать немного каждый раз, а не сразу. К сожалению, метод GC :: Collect () не быстрее, чем чаще вы его называете. Поэтому для механизма реального времени, если вы не можете просто использовать механизм удаления и позволить GC собирать ваши данные, тогда вы не должны использовать управляемую систему - согласно моему ответу (возможно, ниже этого, lol). – Jin 1 February 2012 в 22:46
  • 2
    В моем случае я запускаю алгоритм A * (кратчайший путь), ПОВТОРНО, к настройке производительности ... который в процессе производства будет запускаться только один раз (на каждой «карте»). Поэтому я хочу, чтобы GC выполнялся перед каждой итерацией вне моего «измеряемого блока эффективности», потому что я чувствую, что более точно моделирует ситуацию в производстве, в которой GC может / должен быть принудительно после навигации по каждой «карте», , – corlettk 12 September 2012 в 07:48
  • 3
    Вызов GC перед измеренным блоком фактически не моделирует ситуацию в производстве, потому что в производстве GC будет сделано в непредсказуемое время. Чтобы смягчить это, вы должны предпринять длительные измерения, которые будут включать в себя несколько исполнений GC, и учитывать пики во время GC в вашем анализе и статистике. – Ran 19 December 2012 в 01:03

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

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

8
ответ дан Michael Stum 18 August 2018 в 06:57
поделиться
  • 1
    Вы уверены, что вам это нужно? GC будет собираться, если ему нужна память, даже если ваш код не простаивает. – Konrad Rudolph 24 October 2008 в 14:56
  • 2
    Не уверен, что это сейчас .net 3.5 SP1, но ранее (1.1 и я считаю, что я тестировал против 2.0), это действительно повлияло на использование памяти. GC, конечно же, всегда будет собираться, когда это необходимо, но вы все равно можете потратить 100 мегабайт ОЗУ, когда вам понадобится только 20. Нужно было бы еще несколько тестов – Michael Stum♦ 24 October 2008 в 15:06
  • 3
    GC запускается при распределении памяти, когда поколение 0 достигает определенного порога (например, 1 МБ), а не когда «что-то не работает». В противном случае вы могли бы получить OutOfMemoryException в цикле, просто выделив и сразу же отбросив объекты. – liggett78 24 October 2008 в 15:11
  • 4
    100megs ОЗУ не теряются впустую, если никакие другие процессы не нуждаются в этом. Это дает вам хорошую производительность: -P – Orion Edwards 2 November 2008 в 03:40

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

13
ответ дан Mike de Klerk 18 August 2018 в 06:57
поделиться
  • 1
    компилятор? что делает компилятор с GC? :) – KristoferA 24 September 2009 в 16:36
  • 2
    Ничего, он только компилирует и оптимизирует код. И это определенно не имеет ничего общего с CLR ... или .NET даже. – Kon 17 October 2009 в 17:28
  • 3
    Объекты, занимающие много памяти, такие как очень большие изображения, могут не получить сбор мусора, если вы явно не собираете их. Я думаю, что это (крупные объекты) было проблемой OP, более или менее. – code4life 16 February 2013 в 19:05
  • 4
    Обертка его при использовании будет гарантировать, что он запланирован для GC, когда он выходит из сферы использования. Если компьютер не взрывается, эта память, скорее всего, будет очищена. – Kon 17 February 2013 в 04:30

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

  1. У вас есть что-то в своем коде, который объявляет элементы в большем объеме, чем
  2. Является ли использование памяти действительно слишком высоким
  3. Сравните производительность до и после использования GC.Collect (), чтобы увидеть, действительно ли это помогает.
7
ответ дан Mitch Wheat 18 August 2018 в 06:57
поделиться

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

. NET GC хорошо спроектирован и настроен как адаптивный, что означает, что он может настроить порог GC0 / 1/2 в соответствии с «привычкой» вашей программной памяти Применение. Таким образом, он будет адаптирован к вашей программе через некоторое время. Когда вы вызовете GC.Collect явно, пороговые значения будут сброшены! И .NET должен потратить время, чтобы снова адаптироваться к привычке вашей программы.

Мое предложение всегда является надежным .NET GC. Любые проблемы с памятью, проверьте счетчик производительности «.NET Memory» и диагностируйте мой собственный код.

5
ответ дан Morgan Cheng 18 August 2018 в 06:57
поделиться
  • 1
    Я думаю, что лучше слить этот ответ с вашим предыдущим ответом. – Salamander2007 6 November 2008 в 05:48

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

IMHO, это аналогично высказыванию «Если вы можете доказать, что ваша программа никогда не будет иметь никаких ошибок в будущем, тогда идите вперед ...»

По всей серьезности принудительное использование GC полезно для целей отладки / тестирования. Если вы чувствуете, что вам нужно делать это в любое другое время, то либо вы ошибаетесь, либо ваша программа была построена неправильно. В любом случае, решение не заставляет GC ...

0
ответ дан Orion Edwards 18 August 2018 в 06:57
поделиться
  • 1
    "либо либо вы ошибаетесь, либо ваша программа была построена неправильно. В любом случае, решение не заставляет GC ... & quot; Абсолюты почти всегда не соответствуют действительности. Есть некоторые исключительные обстоятельства, которые имеют смысл. – rolls 12 April 2017 в 03:18

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

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

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

15
ответ дан user 18 August 2018 в 06:57
поделиться

Не уверен, что это лучшая практика ...

Предложение: не реализуйте это или что-нибудь, когда вы не уверены. Переоценивайте, когда факты известны, затем выполните до / после проверок производительности.

1
ответ дан user957965 18 August 2018 в 06:57
поделиться

Я хотел бы добавить, что: вызов GC.Collect () (+ WaitForPendingFinalizers ()) является частью истории. Как справедливо упоминается другими, GC.COllect () является недетерминированным набором и остается на усмотрение самого GC (CLR). Даже если вы добавите вызов WaitForPendingFinalizers, это может быть не детерминированным. Возьмите код из этой ссылки msdn и запустите код с итерацией цикла объекта как 1 или 2. Вы найдете то, что не является детерминированным средством (установите точку прерывания в деструкторе объекта). Точно так же деструктор не вызывается, когда Wait .. () имеет только 1 (или 2) затяжные объекты. [Citation reqd.]

Если ваш код имеет дело с неуправляемыми ресурсами (например: внешний файл дескрипторы).

Вот интересный пример:

Примечание. Если вы уже пробовали пример из MSDN, чтобы очистить воздух.

class Program
{    
    static void Main(string[] args)
        {
            SomePublisher publisher = new SomePublisher();

            for (int i = 0; i < 10; i++)
            {
                SomeSubscriber subscriber = new SomeSubscriber(publisher);
                subscriber = null;
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine(SomeSubscriber.Count.ToString());


            Console.ReadLine();
        }
    }

    public class SomePublisher
    {
        public event EventHandler SomeEvent;
    }

    public class SomeSubscriber
    {
        public static int Count;

        public SomeSubscriber(SomePublisher publisher)
        {
            publisher.SomeEvent += new EventHandler(publisher_SomeEvent);
        }

        ~SomeSubscriber()
        {
            SomeSubscriber.Count++;
        }

        private void publisher_SomeEvent(object sender, EventArgs e)
        {
            // TODO: something
            string stub = "";
        }
    }

Я предлагаю сначала проанализировать, какой результат мог быть, а затем запустить, а затем прочитать причину ниже:

{Деструктор только неявно называется один раз программа заканчивается. } Чтобы детерминистически очистить объект, нужно реализовать IDisposable и сделать явный вызов Dispose (). В этом суть! :)

4
ответ дан Vaibhav 18 August 2018 в 06:57
поделиться
30
ответ дан Ian Ringrose 6 September 2018 в 20:39
поделиться
5
ответ дан Morgan Cheng 6 September 2018 в 20:39
поделиться
30
ответ дан Ian Ringrose 30 October 2018 в 01:58
поделиться
5
ответ дан Morgan Cheng 30 October 2018 в 01:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: